设计稿里的滚动条只有两三个像素宽,浅灰色压在白底上,评审时看着确实清爽。上线之后换成鼠标用户来用,问题就出来了:滑块要瞄半天才按得住,手抖或者精细动作吃力的人更难用。前端能做的事情不算少,可有几个地方经常写错。
scrollbar-width 只有三个档
标准属性 scrollbar-width 只收 auto、thin、none 三个关键字,没法写像素值。MDN 和 CSS Scrollbars 草案都说,这个属性是给局促的区域省点空间用的,不是拿来调外观的。none 只是不显示滚动条,元素照样能滚。草案专门提醒过,这样只用鼠标的人会滚不动内容。
thin 也不保证一定变细。草案的写法是:浏览器应该用更细的滚动条,但必须保持可用。用户在系统或浏览器里表示过不想要细滚动条的话,浏览器可以按 auto 处理。
还有两个细节。这个属性不继承,写在父元素上管不到子元素。页面级的滚动条要写在根元素 html 上才会作用到视口,写在 body 上传不过去。
和 ::-webkit-scrollbar 混用
想要「4px 宽」这种精确值,大家一般会去写 ::-webkit-scrollbar。这个伪元素不在标准里,MDN 不建议在生产环境依赖。两套写法同时存在时,规则是这样的:元素上 scrollbar-width 的计算值只要不是 auto,支持这个标准属性的浏览器就会忽略这个元素上的 ::-webkit-scrollbar 系列样式。
scrollbar-color 也是这样,而且这个属性会继承。在 html 上设了 scrollbar-color,整页的 webkit 滚动条样式可能都会失效,要在某个元素上写回 scrollbar-color: auto 才能恢复。调了半天 webkit 样式不生效,常常是这个原因。
2.5.8 的例外能不能用
WCAG 2.2 的 2.5.8 目标尺寸(最低)是 AA 级:指针操作的目标至少要 24×24 CSS 像素,条文另列了五条例外,其中一条是「目标尺寸由用户代理决定,作者没有改动」。W3C 的 Understanding 文档直接拿浏览器滚动条当这条例外的例子。
按条文理解,原生滚动条本来可以靠这条例外过关,作者一旦把滚动条改细,就不能再拿这条例外当挡箭牌了。Understanding 文档接着写的是:作者改过滚动条尺寸的话,滚动条和页面内容之间就得留够间距。按文档里的检查方法,在滚动条上放一个直径 24 CSS 像素的圆,这个圆不能压到旁边的链接或按钮。这只是我对条文的读法,具体项目算不算达标,还要看你们的验收怎么定。
折中做法
主内容区保留原生滚动条,只在侧栏、下拉列表这种小面板上用 thin,再给不支持标准属性的浏览器留个 webkit 兜底:
html {
scrollbar-gutter: stable;
}
.side-panel {
overflow-y: auto;
scrollbar-width: thin;
}
@supports not (scrollbar-width: thin) {
.side-panel::-webkit-scrollbar {
width: 10px;
}
.side-panel::-webkit-scrollbar-thumb {
background: #888;
border-radius: 5px;
}
}
scrollbar-gutter: stable 是给滚动条预留位置的,内容从不满一屏变成超出一屏时,页面不会左右跳一下。它只对占位的经典滚动条起作用,系统用的是悬浮式滚动条时没有效果。这个属性写在根元素上,同样会作用到视口。页面抖动这件事站里以前有人问过,见 这帖。
另外别忘了键盘。MDN 在 scrollbar-width 的无障碍说明里专门提了 WCAG 2.1.1(键盘)。可滚动的面板用 Tab 能不能进去、方向键能不能滚,各浏览器的默认行为不完全一样,上线前自己按一遍。
滚动条宽度管的是能不能点中。用户把整页放大到 150% 以后布局会不会散,是另一回事,缩放那个问题另说。
你们会把自定义滚动条放进验收清单吗,还是一直交给设计说了算?