深入剖析浏览器滚动条
我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情
前言
为什么要专门写一篇关于浏览器滚动条的文章呢?毕竟定制滚动条属于小众需求。事情源于一次产品上线之后,用户反馈滚动条也太丑了,设计让前端帮忙改一下:要细一些,宽度6px,颜色淡一些,#000000 8%不透明度,hover状态时宽度 10px,颜色 #000000 16%不透明度。
于是借此机会对滚动条做了一番研究,发现这里面的水还是很深的(网上的文章很多关于滚动条的文章都是纰漏百出,人云亦云),在此我把研究结果向大家分享一下,一个小小的滚动条中竟然包含了以下六种伪元素:
::-webkit-scrollbar
——整个滚动区域::-webkit-scrollbar-button
——滚动条两端的按钮(包含上下箭头)::-webkit-scrollbar-track
——滚动条外层轨道::-webkit-scrollbar-track-piece
——滚动条内层轨道(分为上下两部分)::-webkit-scrollbar-thumb
——可拖动的滑块::-webkit-scrollbar-corner
——垂直滚动条和水平滚动条交汇部分(通常在右下角)
可以用下面的一张图来描述上述所有元素:
看起来是不是很复杂?别担心,我会从下面这个基础的原生滚动条开始,带领大家一步步认识上面的各种伪元素:
上面矩形滚动区域的 HTML 结构为:
<div class="container">
<div class="rect">
<div class="box"></div>
</div>
</div>
初始 CSS 样式为:
.container {
margin-top: 50px;
display: flex;
justify-content: space-around;
}
.rect {
width: 600px;
height: 600px;
overflow: scroll;
border: 1px solid gainsboro;
}
.box {
width: 1000px;
height: 1000px;
background: linear-gradient(45deg, #fb3 25%, #58a 0, #58a 50%, #fb3 0, #fb3 75%, #58a 0);
background-size: 42.4264px 42.4264px;
opacity: 0.2;
}
-webkit-scrollbar 伪元素
::-webkit-scrollbar
代表整个滚动条,我们可以为其设置宽高、背景色、边框,例如:
.rect::-webkit-scrollbar {
width: 50px;
height: 50px;
background-color: yellow;
border: 5px solid green;
}
然后滚动条就变成了下面这个样子:
值得注意的是,对于自定义滚动条样式,这个伪类是必不可少的,如果没有设置 ::-webkit-scrollbar
,那么下面所有其他的伪类都无法生效。所以该伪类的一个重要的作用就是告诉控制 webkit 引擎是否使用默认的滚动条样式。
另外需要特别强调的是,在 -webkit-scrollbar
伪类样式中,width 属性只对垂直滚动条起作用,height 属性只对水平滚动条起作用,而这个规则对下面的 -webkit-scrollbar-button
则恰恰相反。
-webkit-scrollbar-button 伪元素
::-webkit-scrollbar-button
伪元素表示滚动条两端的按钮区域。如果是垂直滚动条,按钮在上下两端;如果是水平滚动条,按钮在左右两端。该伪元素要配合以下六个伪类一起使用:
伪类 | 选中的状态 |
---|---|
:horizontal | 当滚动条处于水平方向 |
:vertical | 当滚动条处于垂直方向 |
:decrement | 当点击后减少滚动值 |
:increment | 当点击后增加滚动值 |
:start | 当处于开始位置 |
:end | 当处于结束位置 |
我们增加以下 CSS 代码来设置滚动按钮样式:
.rect::-webkit-scrollbar-button {
display: block;
background-color: rgba(185, 28, 28, 0.8);
background-repeat: no-repeat;
background-size: 50%;
background-position: center;
height: 25px;
width: 25px;
}
.rect::-webkit-scrollbar-button:vertical:start:increment {
background-image: url("https://img.zlib.cn/blog/chevron-down.svg");
}
.rect::-webkit-scrollbar-button:vertical:start:decrement {
background-image: url("https://img.zlib.cn/blog/chevron-up.svg");
}
.rect::-webkit-scrollbar-button:vertical:end:increment {
background-image: url("https://img.zlib.cn/blog/chevron-down.svg");
}
.rect::-webkit-scrollbar-button:vertical:end:decrement {
background-image: url("https://img.zlib.cn/blog/chevron-up.svg");
}
.rect::-webkit-scrollbar-button:horizontal:start:increment {
background-image: url("https://img.zlib.cn/blog/chevron-right.svg");
}
.rect::-webkit-scrollbar-button:horizontal:start:decrement {
background-image: url("https://img.zlib.cn/blog/chevron-left.svg");
}
.rect::-webkit-scrollbar-button:horizontal:end:increment {
background-image: url("https://img.zlib.cn/blog/chevron-right.svg");
}
.rect::-webkit-scrollbar-button:horizontal:end:decrement {
background-image: url("https://img.zlib.cn/blog/chevron-left.svg");
}
效果如下:
刚才上面也讲到,在 -webkit-scrollbar-button
伪元素里面,width 只对水平滚动条两端的按钮起作用,height 只对垂直滚动条两端的按钮起作用。
-webkit-scrollbar-track 伪元素
::-webkit-scrollbar-track
表示滚动条的外层轨道,我们先给它增加以下 CSS 代码看看效果:
.rect::-webkit-scrollbar-track {
background-color: blue;
border: 5px solid orange;
margin: 30px;
}
这里特地增加了 margin 外边距把 scrollbar 本身的背景色给透出来方便大家观察其位置:
上面的蓝色背景橙色边框区域就是外层轨道的,需要注意的是,这里无法单独对其设置 width 或 height 样式,它的宽高始终和 -webkit-scrollbar
的宽高保持一致。既然是外层轨道,说明存在内层轨道,我们继续往下看:
-webkit-scrollbar-track-piece 伪元素
::-webkit-scrollbar-track-piece
是滚动条的内层轨道,这个就有点意思了,为了看起来更有辨识度,我们用颜色区分出来:
.rect::-webkit-scrollbar-track-piece {
background-color: green;
border: 5px solid purple;
margin: 30px;
}
细心的你可能已经发现了,这次的样式非常奇怪,因为中间有一道杠:
这是因为内层轨道其实是有两部分组成的,垂直滚动条的内层轨道被分为上下部分,水平滚动条的内层轨道被分为左右两部分,而每一部分都可以用 start
或 end
伪类来控制,例如设置不同的背景色:
/* 控制滚动区域的上/左半部分 */
.rect::-webkit-scrollbar-track-piece:start {
background-color: yellowgreen;
}
/* 控制滚动区域的下/右半部分 */
.rect::-webkit-scrollbar-track-piece:end {
background-color: greenyellow;
}
通过设置背景色区分,可以看到更明显的看到上下/左右两部分的范围了:
-webkit-scrollbar-thumb 伪元素
::-webkit-scrollbar-thumb
才是滚动条的滑块,也就是可拖动的部分,我们用下面的 CSS 把它展现出来:
.rect::-webkit-scrollbar-thumb {
background-color: rgba(128, 0, 128, 0.5);
border-radius: 30px;
}
可以看到滚动滑块的中间恰好是内层轨道上下/左右两部分的交界处:
这里有一点需要特别注意,很多人想通过 width 来修改垂直滑块的宽度,或者通过 height 来修改水平滑块的高度,其实都是不可行的,因为它的宽高永远和 -webkit-scrollbar
保持一致,那怎样从视觉上让其变得更窄一点呢?这里要用到 background-clip
这个 CSS 属性:
background-clip 用于设置元素的背景(包括背景颜色或背景图片)是否延伸到边框、内边距盒子和内容盒子下面。
它可以有以下取值:
background-clip: border-box
:背景延伸至 border 外沿background-clip: padding-box
:背景延伸至 padding 外沿background-clip: content-box
:背景延伸至 content 外沿background-clip: text
:背景剪裁成文字的前景色
我们给滚动滑块设置边框透明和背景范围:
.rect::-webkit-scrollbar-thumb {
background-color: rgba(128, 0, 128, 0.5);
border-radius: 30px;
border: 15px solid transparent; /* 设置边距透明 */
background-clip: padding-box; /* 设置背景范围 */
}
可以看到从视觉上看滚动滑块的宽度/高度发生了改变:
-webkit-scrollbar-corner 伪元素
::-webkit-scrollbar-corner
是垂直滚动条和水平滚动条交界的部分,我们可以单独控制其样式,例如添加背景色:
.rect::-webkit-scrollbar-corner {
background-color: #7f1d1d;
}
注意看到右下角区域的变化:
学习总结
讲完这六个伪元素,再回过来看下面的图,就非常清晰了:
可以看到滚动条在设计上是非常复杂的,但正因为此,才可以满足更多的个性化定制需求,虽然带有 -webkit-
前缀,不是 w3c 标准,但是由于 Chrome 一统天下,这已经成为事实上的浏览器标准了。
实战
再回到最初的需求:要细一些,宽度6px,颜色淡一些,#000000 8%不透明度,hover状态时宽度 10px,颜色 #000000 16%不透明度。假设现在滚动区域是一个类为 rect 的 div,结构如下:
<div class="rect">
<!-- 滚动区域 -->
</div>
最初写的 CSS 代码如下:
.rect::-webkit-scrollbar {
width: 6px;
height: 0;
background-color: transparent;
}
.rect::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.08);
}
.rect::-webkit-scrollbar-thumb:hover {
width: 10px;
background-color: rgba(0, 0, 0, 0.16);
}
结果发现滚动条的颜色生效了,但是 hover 上去之后宽度并没有变宽,这是因为为 -webkit-scrollbar-thumb
单独设置宽度是无效的,必须借用 background-clip
来实现类似效果:
.rect::-webkit-scrollbar {
width: 10px;
height: 0;
background-color: transparent;
}
.rect::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.08);
border-left: 4px solid transparent;
background-clip: padding-box;
}
.rect::-webkit-scrollbar-thumb:hover {
background-color: rgba(0, 0, 0, 0.16);
border: 0;
}
最终效果如下:
转载自:https://juejin.cn/post/7139049177656819749