- let data = [0, 12, 16, 24, 32, 48, 64, 128, 256, 512];
- let min = 0, max = data.length - 1;
- let a = Math.round(.25*max);
- let b = Math.round(.5*max);
.wrap(role='group' aria-label='multi thumb slider with ruler' style=`--a: ${a}; --b: ${b}; --min: ${min}; --max: ${max}; --lbl-a: ${data[a]}; --lbl-b: ${data[b]}`)
label.sr-only(for='a') Value A:
input#a(type='range' min=min max=max value=a aria-valuetext=data[a] list='l')
output(for='a' aria-hidden='true')
output(for='a' aria-hidden='true')
output(for='a' aria-hidden='true')
label.sr-only(for='b') Value B:
input#b(type='range' min=min max=max value=b aria-valuetext=data[b] list='l')
output(for='b' aria-hidden='true')
output(for='b' aria-hidden='true')
output(for='b' aria-hidden='true')
datalist#l
- for(let i = 0; i <= max; i++)
option(value=i label=data[i])
View Compiled
$c0: #e6450f;
$c1: #fff;
$track-h: 1rem;
$thumb-d: 1.5rem;
$label-h: 3rem;
@mixin track() {
border: none;
padding: 0;
width: 100%; height: $track-h;
background: none;
color: transparent
}
@mixin thumb($m: 0) {
box-sizing: border-box;
margin-top: $m;
border: none;
width: $thumb-d; height: $thumb-d;
border-radius: 50%;
box-shadow:
0 1px .125em rgba(#ae725a, .5),
0 1px .25em rgba(#ae725a, .5);
background: #eae9ea;
transition: none;
pointer-events: auto;
cursor: pointer
}
%mid {
grid-column: 2;
grid-row: 2;
place-self: center;
width: var(--track-w);
pointer-events: none
}
* {
--hl: 0;
--nothl: calc(1 - var(--hl));
margin: 0;
padding: 0;
background: none;
font: inherit
}
html {
--i: var(--wide, 1);
--j: var(--narr, 0);
--notj: calc(1 - var(--j));
display: grid;
place-content: center;
overflow-x: hidden;
height: 100vh;
background: $c0;
color: $c1;
font: 300 1em/ 1.5 quicksand, trebuchet ms, sans-serif;
@media (min-width: 750px) { font-size: 1.25em }
@media (max-width: 570px) { --wide: 0 }
@media (max-width: 440px) { --narr: 1 }
@media (max-width: 320px) { font-size: .75em }
&:not(.js) {
output, .wrap::after { visibility: hidden }
}
}
.wrap {
--u: calc(var(--notj)*2.75rem + var(--j)*10vw);
--n-cols: calc(var(--max) + 1);
--middl-w: calc(var(--n-cols)*var(--u));
--label-w: calc(var(--i)*5rem);
--track-w: calc(var(--middl-w) - var(--u) + #{$thumb-d});
--m: calc(.5*(var(--a) + var(--b)));
display: grid;
grid-auto-flow: row dense;
grid-template-rows: $label-h max-content $label-h;
grid-template-columns: var(--label-w) var(--middl-w) var(--label-w);
filter: brightness(.8);
&::before, &::after {
@extend %mid;
z-index: -1;
height: $track-h;
border-radius: $track-h;
content: ''
}
&::before {
box-shadow: 0 1px #fc7444;
background: linear-gradient(#9b2f0b, #bc3c0f)
}
&::after {
background: #ecebe9;
mask:
linear-gradient(90deg,
red calc(#{.5*$thumb-d} + var(--a)*var(--u)),
transparent 0) exclude,
linear-gradient(90deg,
red calc(#{.5*$thumb-d} + var(--b)*var(--u)),
transparent 0)
}
&:focus-within { filter: none }
}
.sr-only {
position: absolute;
clip-path: inset(50%)
}
input[type='range'] {
&, &::-webkit-slider-thumb,
&::-webkit-slider-runnable-track {
appearance: none
}
@extend %mid;
min-height: 1.5*$thumb-d; height: 1.5*$track-h;
background: none;
&::-webkit-slider-runnable-track { @include track() }
&::-moz-range-track { @include track() }
&::-webkit-slider-thumb { @include thumb(calc(.5*(#{$track-h} - #{$thumb-d}))) }
&::-moz-range-thumb { @include thumb() }
& + [for] {
display: grid;
justify-self: start;
margin-left: calc(.5*var(--u));
padding-bottom: .75rem;
transform: translate(calc(var(--c)*var(--u) - 50%));
&::after {
display: block;
padding: .25em .75em;
transform-origin: 50% 100%;
transform: scale(var(--hl));
border-radius: .25em;
box-shadow:
inset 0 0 2px #ff7747,
inset 0 0 .25em #bc3c0f,
inset 0 0 .5em #cf3f10,
0 1px #fc7444;
opacity: var(--hl);
transition: .3s ease-out;
transition-property: transform, opacity
}
}
&, & + [for] { grid-column: 2 }
&:focus {
outline: solid 0 transparent;
&, & + [for] { --hl: 1 }
}
}
output[for] {
grid-row: 1;
font-size: 1.25em;
font-weight: 600;
counter-reset: lbl var(--lbl);
&:after {
content: counter(lbl) ' px'
}
& + & {
--k: var(--parity, 1);
--notk: calc(1 - var(--k));
--sgnk: calc(1 - 2*var(--k));
grid-column: calc(2*var(--notk) + 1);
align-self: center;
justify-self: var(--parity, end);
overflow: hidden;
grid-row-end: span 3;
opacity: calc(4*var(--sgnk)*(var(--c) - var(--m)) + 1);
color: rgba($c1, calc(var(--i)))
}
&:nth-of-type(3n) {
--parity: 0;
}
}
output[for='a'] { --c: var(--a); --lbl: var(--lbl-a) }
output[for='b'] { --c: var(--b); --lbl: var(--lbl-b) }
datalist {
display: grid;
grid-auto-flow: column;
grid-row: 3;
place-self: start stretch;
width: var(--middl-w);
}
option {
display: flex;
flex-direction: column;
justify-content: center;
width: var(--u);
font-size: var(--notj);
text-align: center;
&::before {
align-self: center;
width: 4px; height: .75rem;
box-shadow: inset -1px 0 1px #fc7777;
background: #9b2f0b;
content: ''
}
&:not(:nth-child(3n + 1)) { color: rgba($c1, var(--notj)) }
}
View Compiled
document.documentElement.classList.add('js');
addEventListener('input', e => {
let _t = e.target,
_p = _t.parentNode,
val = +_t.value,
_o = _p.querySelector(`option[value='${val}']`),
lbl = +_o.label;
_t.setAttribute('aria-valuetext', lbl);
_p.style.setProperty(`--${_t.id}`, val);
_p.style.setProperty(`--lbl-${_t.id}`, lbl);
}, false);