OverlayScrollbars 入门:自定义滚动条
浏览器原生滚动条丑得千篇一律,还各平台长得不一样。OverlayScrollbars 一套 CSS 变量让滚动条全平台统一、可定制、不占布局空间。
问题:原生滚动条的三宗罪
样式不可控。Windows 的灰色粗条、macOS 的自动隐藏细条、Linux 的各种花样——同一个页面在不同系统上观感割裂,而原生滚动条能用 CSS 定制的只有 ::-webkit-scrollbar(Chrome/Safari 专属,Firefox 不认)。
占布局空间。原生滚动条挤压内容宽度,滚动条出现/消失时内容会跳动(layout shift)。
嵌套滚动难以区分。页面滚和内层容器滚混在一起时,两个长得一样的滚动条让用户分不清在滚哪一层。
OverlayScrollbars 的方案:把原生滚动条隐藏掉,用真实的 DOM 元素画一条覆盖在内容之上的滚动条(overlay 之意),跨浏览器像素级一致,且不占内容空间。
接入
pnpm add overlayscrollbars overlayscrollbars-vue # Vue 适配(React/Svelte 也有对应包)
// 全局初始化(针对 body 滚动)
import 'overlayscrollbars/overlayscrollbars.css';
import { OverlayScrollbars, ScrollbarsHidingPlugin } from 'overlayscrollbars';
OverlayScrollbars(document.body, {
scrollbars: {
theme: 'os-theme-custom',
autoHide: 'move', // 滚动时显示、停下后淡出
pointers: ['mouse', 'touch', 'pen'],
},
overflow: { x: 'hidden', y: 'scroll' },
});
<!-- 容器级:Vue 组件包一层 -->
<script setup>
import { OverlayScrollbarsComponent } from 'overlayscrollbars-vue';
</script>
<template>
<OverlayScrollbarsComponent
element="div"
:options="{ scrollbars: { autoHide: 'leave' } }"
class="chat-panel"
>
<MessageItem v-for="m in messages" :key="m.id" :msg="m" />
</OverlayScrollbarsComponent>
</template>
主题定制:CSS 变量
滚动条的外观就是一组 CSS,改起来直白:
.os-theme-custom {
--os-handle-bg: rgba(148, 163, 184, 0.35); // 滑块颜色
--os-handle-bg-hover: rgba(148, 163, 184, 0.6); // 悬停加深
--os-size: 10px; // 粗细
--os-border-radius: 999px; // 全圆角
--os-padding-perpendicular: 3px; // 距边缘内边距
}
配合站点的深浅色主题在 :root 切换变量,滚动条和主题天然一体。本站全站滚动条都走了这套定制,深浅色下观感一致。
它处理掉的那些暗坑
自绘滚动条听起来简单,坑其实都在细节,这也是用库而不是手写的理由:
滚轮/触摸事件与滚动同步。自绘元素不响应滚轮,库要做事件桥接,保证滚轮、触摸板惯性、拖动滑块三种交互都顺滑。
position: sticky 兼容。把滚动条从容器「剥离」出来的实现方式会破坏 sticky 定位,OverlayScrollbars 有 ScrollbarsHidingPlugin 专门处理这一类冲突。
RTL 布局。阿拉伯语等从右到左的布局,滚动方向逻辑不同,库内已处理。
无障碍。保持键盘滚动(方向键、PageUp/Down)可用,focus 样式不丢——自绘方案最容易丢的就是这块。
autoHide 的分寸
autoHide: 'move'(滚动时显示)适合内容区——沉浸阅读时滚动条不该一直杵在那;autoHide: 'never' 适合功能性面板(聊天窗、代码预览)——用户需要随时知道「这里能滚、滚到哪了」。可发现性优先于美观,不确定时选 never。
小结
OverlayScrollbars 用「真实元素模拟滚动条」换来了跨平台一致与完全可定制,同时把滚轮桥接、sticky、RTL、无障碍这些暗坑全部消化。接入姿势:全局初始化管 body,容器组件管局部滚动,CSS 变量管外观。它是那种用户说不出名字、但会显著影响「这个网站做得细不细」的观感件。