UX experience: Customize range input like Apple IOS slider
May 15, 2023
Preface
One day I found out that Apple IOS has a very beautiful slider and it inspired me to build a similar input range slider with HTML. After a few hours of try and errors, I finally built one. Here is the result.
Termology
- thumb: The draggable part of the slider
- track: The bar that the thumb slides along
- progress track: The part of the track that is filled with color
Lessons learned
OnMouceUp/OnMouseDown vs OnMouseEnter/OnMouseLeave
Initially, I used onmouseenter
and onmouseleave
to control the color of the progressed track, but because the track height is small, once the user’s cursor leaves the input, the color will change which results in a flickering effect. So I changed to onmousedown
and onmouseup
to control the color of the progressed track.
Wipe out the default style
Different browsers have different default styles for the input range. To make the slider looks consistent across all browsers, we need to wipe out the default style. 1
/* Remove the basic style */
input[type="range"] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: none;
outline: none;
}
/* Remove the track style */
/* Chrome, Safari, Opera, and Edge Chromium */
input[type="range"]::-webkit-slider-runnable-track {
height: 0.3rem;
opacity: 60%;
}
/* Firefox */
input[type="range"]::-moz-range-track {
height: 0.5rem;
opacity: 60%;
}
But the caveat is that you can’t remove the appearance of the thumb or the interaction will break. So we need to set the thumb to transparent.
/* Chrome, Safari, Opera, and Edge Chromium */
input[type="range"]::-webkit-slider-thumb {
opacity: 0;
}
/* Firefox */
input[type="range"]::-moz-range-thumb {
opacity: 0;
}
How to color progress track
There are multiple ways to accomplish this.
- Use
linear-gradient
to create a gradient background - Use
box-shadow
to create a shadow from the thumb and hide the overflow box-shadow 2
I think the second method is not reliable, especially since we want to achieve a transparent thumb experience. So I used the first method.
input[type="range"] {
background-image: linear-gradient(to right, #ff0000 0%, #ff0000 50%, #ffffff 50%, #ffffff 100%);
}
The first and the second color is the color of progressed track and the third and the fourth color is the color of the rest of the track. You need to calculate the percentage of the progressed track.
Be careful of the min and max when calculating the percentage.
<input
type="range"
value={sliderValue()}
style={{
"background-image": `linear-gradient(to right,
${progressTrackColor()} 0%, ${progressTrackColor()}
${((sliderValue() - min) / (max - min)) * 100}%, ${trackColor}
${((sliderValue() - min) / (max - min)) * 100}%, ${trackColor} 100%)`,
}}
min={min}
max={max}
/>
How to accomplish the hover and mouseleave using different animation
In short, we can set the default transition for non-hover events and override the transition for hover events.
input[type="range"] {
transition: transform 0.6s ease-in-out;
/*
We use this to override the default transition to accomplish
different animation between mouseenter and mouseleave
*/
&:hover {
transform: scaleY(1.75);
transition: transform 0.15s ease-out;
}
}
Left for future experiment
Overall the range works great on the desktop but the experience is terrible on the mobile. When you click the range bar it can’t smoothly focus on the thumb and move with your touch moves. At first glance the package range-touch looks promising. But I would like to find a more lightweight solution without importing another package