CSS Tip! 🤯
You can create a CSS-only version of this balance slider using a scroll animation on the underlying input[type=range] 🚀
::-webkit-slider-thumb {
view-timeline: --thumb inline;
}
Scroll animation driven by the slider thumb animates a number between the "min" and "max" of the range 😅
@property --value {
inherits: true;
initial-value: 0;
syntax: '<integer>';
}
@keyframes sync { to { --value: 100; }}
Tie that up to the contain animation-range ⚡️
.control {
animation: sync both linear reverse;
animation-timeline: --thumb;
animation-range: contain;
}
Hoist the view timeline so all the parts of the control can use it!
.control { timeline-scope: --thumb; }
Use that value in a counter which is used for the labels. Create a low and a high for each side 😇
.control__label {
counter-reset:
low var(--value)
high calc(100 - var(--value));
}
.control__label::before {
content: "COFFEE " counter(low) "%";
}
.control__label::after {
content: counter(high) "% MILK";
}
That's the magic of updating the label values ✨
For the big track, it's a fake track. You can make use of the same --value property and do some calc() to work out the width of each part.
<div class="control__track">
<div class="control__indicator"></div>
</div>
.control__track::before {
width: calc(var(--value) * 1% - 0.5rem);
background: var(--coffee);
border-radius: 4px;
transition: width 0.1s;
}
The width leaves a little gap for the indicator piece 🤙
The color calculation for --coffee isn't too wild but again you can use the same --value
.control__track {
--coffee: hsl(24 74% calc(
24% (30% * ((100 - var(--value, 0)) / 100)) / 1
) / 0.4);
}
Now for the last piece. Making the track change height. You could set up another custom property and animate its value using the --thumb timeline too 🔥
@property --shift {
initial-value: 0;
inherits: true;
syntax: '<integer>';
}
@keyframes shift {
0%, 31%, 61%, 100% { --shift: 0; }
32%, 60% { --shift: 1; }
}
Then use that --shift to update the translation of the label and height of the track 🤓
.label {
transform: translateY(calc(var(--shift) * 50%));
transition: transform var(--speed) var(--timing);
}
Cool part here is that you can use the control to work out the @keyframes percentages 😅
Oh. And the timing for that little bounce? Use the linear() function 😎
:root {
--timing: linear(
0, 0.5007 7.21%, 0.7803 12.29%,
0.8883 14.93%, 0.9724 17.63%,
1.0343 20.44%, 1.0754 23.44%,
1.0898 25.22%, 1.0984 27.11%,
1.1014 29.15%, 1.0989 31.4%,
1.0854 35.23%, 1.0196 48.86%,
1.0043 54.06%, 0.9956 59.6%,
0.9925 68.11%, 1
);
}
Should probably do a video on this one. Lots of little custom property tricks for sure! 💯 It's not too far off the range slider with the tooltip that came up previously
As always, any questions, let me know! Also, this one only works in Chrome currently ✅🥲
This one's a bit rocket science ha 🚀
@CodePen link below! 👇
Prototyped a balance slider today ✨
How do you like your coffee?