自定义范围滑块
背景
原生的 HTML5 控件 range input,每个浏览器的样式不同,为了达到统一的样式效果,我们通常有两种方案可以考虑,直接修改 css 样式,或者模拟出一个滑块控件。
解决方案一
直接修改 css 样式。用-webkit-slider-thumb
修改滑块样式,用-webkit-slider-runnable-track
修改轨道样式,再结合:focus
和 :hover
等事件响应加上特效,让滑块更生动。
下面介绍下如何仅通过 css 来控制 input range 的样式。
做一个简单的演示
或者点击我们的 在线 Demo
兼容性
我们这里演示了webkit
下的滑块样式,要想支持更多浏览器,还需要设置不同的伪类
::-webkit-slider-thumb
针对 webkit/blink 设置滑块::-moz-range-thumb
针对火狐设置滑块::-ms-thumb
针对 IE 设置滑块
还有背景条的设置
::-webkit-slider-runnable-track
针对 webkit/blink 设置背景条::-moz-range-track
针对火狐设置背景条::-ms-track
/::-ms-fill-lower
/::-ms-fill-upper
针对 IE 设置背景条
小技巧
我们在滑动条的中间位置放置了一条竖线,用于提示中间位置,竖线符号除了使用按键shift+\
打出来之外,还有以下一些竖线的符号可以使用。
丨 | │ | ᅵ | ▎ | ▍ | ▌ |
▋ | ▊ | ▉ | ǀ | ǁ | ׀ |
ا | ། | ༎ | ᅵ | ‖ | ∣ |
∥ | ⑊ | │ | ┃ | ║ | ╵ |
╷ | ╹ | ╻ | ▅ | ▆ | ▇ |
█ | ▐ | ▕ | ◫ | ▥ | ▯ |
▮ | ❘ | ❙ | ❚ | 〡 | 〢 |
| | ﺍ | ︳ | ︲ | ︱ | ﺍ |
〣 | ㅣ | ㆐ | 丨 |
解决方案二
模拟出一个滑块控件。比如用div
元素模拟 range input 样式,用pointdown
、pointmove
、pointup
等事件等来模拟 input 的行为
代码如下
<div id="container">
<div id="slider" class="slider">
<div class="thumb"></div>
</div>
<div class="rate">50%</div>
</div>
整理下样式
#container {
margin: 30% auto;
width: 300px;
text-align: center;
}
.slider {
border-radius: 6px;
background: #e0e0e0;
height: 10px;
}
.thumb {
touch-action: none;
width: 20px;
height: 20px;
border-radius: 20px;
position: relative;
left: 140px;
top: -5px;
background: gray;
cursor: pointer;
transition: transform 0.3s;
}
.rate {
margin-top: 20px;
}
编写事件
let thumb = slider.querySelector(".thumb");
let rate = container.querySelector(".rate");
let shiftX;
const total = slider.offsetWidth - thumb.offsetWidth;
function onThumbDown(event) {
event.preventDefault(); // prevent selection start (browser action)
shiftX = event.clientX - thumb.getBoundingClientRect().left;
thumb.setPointerCapture(event.pointerId);
thumb.style.transform = "scale(1)";
thumb.onpointermove = onThumbMove;
thumb.onpointerup = (event) => {
// dragging finished, no need to track pointer any more
// ...any other "drag end" logic here...
thumb.onpointermove = null;
thumb.onpointerup = null;
thumb.style.transform = "scale(1.2)";
};
}
function onThumbMove(event) {
let newLeft = event.clientX - shiftX - slider.getBoundingClientRect().left;
// if the pointer is out of slider => adjust left to be within the boundaries
if (newLeft < 0) {
newLeft = 0;
}
let rightEdge = slider.offsetWidth - thumb.offsetWidth;
if (newLeft > rightEdge) {
newLeft = rightEdge;
}
thumb.style.left = newLeft + "px";
setRate(newLeft);
}
function onThumbEnter(event) {
thumb.style.transform = "scale(1.2)";
}
function onThumbLeave(event) {
thumb.style.transform = "scale(1)";
}
function setRate(left) {
rate.innerText = ((left / total) * 100).toFixed(0) + "%";
}
thumb.onpointerdown = onThumbDown;
thumb.onpointerenter = onThumbEnter;
thumb.onpointerleave = onThumbLeave;
thumb.ondragstart = () => false;
看下实际效果
参考
更多的详细解读请参考以下博文
评论