跳转到内容

Scrollbar 滚动条 ​

为现有滚动容器提供一致的滚动条样式。

用法 ​

为滚动容器添加滚动条

项目概览
组件规范
设计令牌
无障碍
交互状态
主题配置
发布记录
迁移指南

组件结构 ​

加粗的是必需部件。

data-scope="scrollbar":root · track · thumb · corner

示例 ​

键盘操作 ​

让滑块可聚焦

第 1 列
第 2 列
第 3 列
第 4 列
第 5 列
第 6 列
第 7 列
第 8 列
第 9 列
第 10 列
第 11 列
第 12 列
第 13 列
第 14 列
第 15 列
第 16 列
第 17 列
第 18 列
第 19 列
第 20 列
第 21 列
第 22 列
第 23 列
第 24 列

双轴滚动 ​

同时显示横向和纵向滚动条

1-11-21-31-41-51-61-71-81-91-101-111-12
2-12-22-32-42-52-62-72-82-92-102-112-12
3-13-23-33-43-53-63-73-83-93-103-113-12
4-14-24-34-44-54-64-74-84-94-104-114-12
5-15-25-35-45-55-65-75-85-95-105-115-12
6-16-26-36-46-56-66-76-86-96-106-116-12
7-17-27-37-47-57-67-77-87-97-107-117-12
8-18-28-38-48-58-68-78-88-98-108-118-12
9-19-29-39-49-59-69-79-89-99-109-119-12
10-110-210-310-410-510-610-710-810-910-1010-1110-12
11-111-211-311-411-511-611-711-811-911-1011-1111-12
12-112-212-312-412-512-612-712-812-912-1012-1112-12
13-113-213-313-413-513-613-713-813-913-1013-1113-12
14-114-214-314-414-514-614-714-814-914-1014-1114-12
15-115-215-315-415-515-615-715-815-915-1015-1115-12
16-116-216-316-416-516-616-716-816-916-1016-1116-12
17-117-217-317-417-517-617-717-817-917-1017-1117-12
18-118-218-318-418-518-618-718-818-918-1018-1118-12
19-119-219-319-419-519-619-719-819-919-1019-1119-12
20-120-220-320-420-520-620-720-820-920-1020-1120-12
21-121-221-321-421-521-621-721-821-921-1021-1121-12
22-122-222-322-422-522-622-722-822-922-1022-1122-12
23-123-223-323-423-523-623-723-823-923-1023-1123-12
24-124-224-324-424-524-624-724-824-924-1024-1124-12
25-125-225-325-425-525-625-725-825-925-1025-1125-12
26-126-226-326-426-526-626-726-826-926-1026-1126-12
27-127-227-327-427-527-627-727-827-927-1027-1127-12
28-128-228-328-428-528-628-728-828-928-1028-1128-12
29-129-229-329-429-529-629-729-829-929-1029-1129-12
30-130-230-330-430-530-630-730-830-930-1030-1130-12

显示方式 ​

设置滚动条的显示时机

type="scroll-hover"
第 1 行
第 2 行
第 3 行
第 4 行
第 5 行
第 6 行
第 7 行
第 8 行
第 9 行
第 10 行
第 11 行
第 12 行
第 13 行
第 14 行
第 15 行
第 16 行
第 17 行
第 18 行
第 19 行
第 20 行
第 21 行
第 22 行
第 23 行
第 24 行
第 25 行
第 26 行
第 27 行
第 28 行
第 29 行
第 30 行
type="auto"
第 1 行
第 2 行
第 3 行
第 4 行
第 5 行
第 6 行
第 7 行
第 8 行
第 9 行
第 10 行
第 11 行
第 12 行
第 13 行
第 14 行
第 15 行
第 16 行
第 17 行
第 18 行
第 19 行
第 20 行
第 21 行
第 22 行
第 23 行
第 24 行
第 25 行
第 26 行
第 27 行
第 28 行
第 29 行
第 30 行
type="always"
第 1 行
第 2 行
第 3 行
第 4 行
第 5 行
第 6 行
第 7 行
第 8 行
第 9 行
第 10 行
第 11 行
第 12 行
第 13 行
第 14 行
第 15 行
第 16 行
第 17 行
第 18 行
第 19 行
第 20 行
第 21 行
第 22 行
第 23 行
第 24 行
第 25 行
第 26 行
第 27 行
第 28 行
第 29 行
第 30 行
type="scroll"
第 1 行
第 2 行
第 3 行
第 4 行
第 5 行
第 6 行
第 7 行
第 8 行
第 9 行
第 10 行
第 11 行
第 12 行
第 13 行
第 14 行
第 15 行
第 16 行
第 17 行
第 18 行
第 19 行
第 20 行
第 21 行
第 22 行
第 23 行
第 24 行
第 25 行
第 26 行
第 27 行
第 28 行
第 29 行
第 30 行
type="hover"
第 1 行
第 2 行
第 3 行
第 4 行
第 5 行
第 6 行
第 7 行
第 8 行
第 9 行
第 10 行
第 11 行
第 12 行
第 13 行
第 14 行
第 15 行
第 16 行
第 17 行
第 18 行
第 19 行
第 20 行
第 21 行
第 22 行
第 23 行
第 24 行
第 25 行
第 26 行
第 27 行
第 28 行
第 29 行
第 30 行

设计指引 ​

何时使用 ​

  • 需要统一不同平台的滚动条样式。
  • 需要为已有滚动容器补充自定义滚动条。

何时不用 ​

  • 需要完整的滚动容器时,使用滚动区域。
  • 只需调整原生滚动条宽度时,优先使用 CSS。

特性 ​

  • 支持五种显示时机,默认在滚动或悬停时显示。
  • 默认使用透明轨道与半透明中性滑块,悬停和拖动时逐级增强。
  • 三档厚度为 4 / 6 / 8px;组件内部保留原生滚动时也复用相同的透明轨道与低对比滑块色阶,作者自建的滚动容器加 data-xh-scroll 即得同一套细条。
  • 支持拖动、点击轨道、键盘操作与 RTL。
  • 支持横向、纵向和双轴滚动。
  • 触屏设备默认保留原生滚动体验。

组合 ​

  • 可与表格、虚拟滚动和日志组合使用。
  • 日期、时间和年份网格等组件内部滚动面复用本组件的透明轨道、厚度和滑块色阶;需要完整自绘交互时组合 root、track 与 thumb。
  • 双轴滚动时使用 gutter 和 corner 处理交叉区域。
  • 多个滚动层并排共用一个定位壳(级联的列、时间列)时,anchor 取 layer,每层各自一套滚动条贴在该层的盒子上。

最佳实践 ​

  • 保留滚动容器的原生滚轮和键盘能力。
  • 触摸设备不要仅使用 hover 显示模式。

反模式 ​

  • 不要为每条辅助滚动条都启用 focusable。
  • 不要用滚动条组件拦截滚轮事件。

API 参考 ​

产物 ​

层值
自定义元素<xh-scrollbar>
Vue 组件XhScrollbarCorner XhScrollbarRoot XhScrollbarThumb XhScrollbarTrack
组合式函数useScrollbar
状态机scrollbarMachine
皮肤@xihan-ui/styles/scrollbar.css

Props ​

属性类型必填说明
orientationOrientation该滚动条管理的轴,默认 vertical。
typeScrollbarType显示的时机,默认 scroll-hover。
hideDelaynumber收起前的等待毫秒(type 为 scroll / hover / scroll-hover 时生效),默认 600。
minThumbSizenumber滑块的最小像素长度,默认 20。长文档中的滑块再短也可按下。
stepnumber方向键一步滚动的像素数,默认 40。翻页键按视口长度计算,不使用该值。
sizeSize尺寸:sm / md / lg,影响滚动条厚度。
anchorScrollbarAnchor根节点的锚定方式,默认 shell。layer 时根节点按滚动层在壳内的偏移盒以内联样式定位, 壳必须是滚动层的定位祖先(offsetParent);该值在状态机生命周期内不应变化。
disabledboolean禁用:不接受指针也不接受键盘,恒不显示。
focusableboolean滑块进入 Tab 序列并报告 role=scrollbar,默认 false。 默认不进入:滚动容器自身已能用键盘滚动,再给每条滚动条一个 Tab 停靠点, 长页面上会多出许多停靠点。需要键盘操作滑块本身时才开启。
controlsstring被控滚动容器的 id;focusable 时写到滑块的 aria-controls 上(未提供时使用容器自身的 id)。
gutterboolean横竖两条同时存在时,各自在末端让出交叉口的一格:竖条不伸到底、横条不伸到头。 交叉口由其中一条中的 corner 部件补上。
forceVisibleboolean触屏设备(粗指针)上也显示,默认 false:触屏没有悬停、拖动滑块也不如直接划动内容, 默认交给原生滚动,本组件整条不显示并带 data-native。
dirDirection排版方向,默认随文档。只影响横轴:RTL 下滚动量的正负、指针位移的方向都要翻转。 必须显式提供:组件不读取计算样式,无法感知从 RTL 祖先继承的方向。
translationsPartial<ScrollbarTranslations>
onScrollStart(details: ScrollbarScrollDetails) => void开始滚动(停止 120ms 才视为一段结束,中途连续滚动不重复通知)。
onScrollEnd(details: ScrollbarScrollDetails) => void一段滚动结束。
onDragStart(details: ScrollbarScrollDetails) => void按住滑块。
onDragEnd(details: ScrollbarScrollDetails) => void松开滑块。

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
nameCustomEvent
scroll-start``开始滚动;detail 为 { offset: number, max: number }
scroll-end``一段滚动结束(停止 120ms);detail 同上
drag-start``按住滑块;detail 同上
drag-end``松开滑块;detail 同上

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhScrollbarRootdefaultScrollbarRootSlotProps

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhScrollbarRootscrollableScrollbarTarget真正在滚动的元素,或者取它的函数。它不必是本组件的后代: 表格的滚动盒、虚拟滚动的视口、任意 overflow:auto 的 div 均可。
XhScrollbarRootchildrenSlotChildren<ScrollbarRootSlotProps>

状态 ​

公开状态写入 data-state。

部件取值
root'visible' | 'hidden'
corner'visible' | 'hidden'

以下名称仅用于内部状态机。

状态:hidden · visible · hiding · dragging

事件:MEASURE · SCROLL · SCROLL.IDLE · POINTER.ENTER · POINTER.LEAVE · DRAG.START · DRAG.MOVE · DRAG.END · TRACK.CLICK · STEP · SCROLL.TO · after.hideDelay

判据:showsOnHover · showsOnScroll · staysVisible · canInteract

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
orientationOrientation
typeScrollbarType
overflowboolean内容比可视区长。不溢出时 auto 档整条不显示。
visibleboolean当前是否应显示(已把 type、disabled 与触屏原生路径都计算在内)。
nativeboolean已交给原生滚动:粗指针设备且未开启 forceVisible,整条不显示。
hoverboolean指针当前在滚动容器或滚动条上。
draggingboolean指针按在滑块上。
scrollingboolean本段滚动仍在进行中。
thumbSizenumber滑块长度占轨道的比例,0-1。
thumbOffsetnumber滑块起点占轨道的比例,0-1。
scrollnumber距逻辑起始缘的滚动量(px)。
maxnumber仍可向前滚动的距离(px)。
scrollTo(offset: number) => void滚动到某个绝对位置(px),越界自动夹取。
scrollBy(delta: number) => void相对当前位置滚动若干像素。
measure() => void重新测量。内容长度变化会自动重新测量(MutationObserver 观察容器子树), 该出口留给无法测量的情况:容器更换、内容在 Shadow DOM 中、或自定义元素内部修改。
getRootProps() => T['element']
getTrackProps() => T['element']
getThumbProps() => T['element']
getCornerProps() => T['element']交叉口补丁,写在其中一条的 root 中;随该条的显隐变化。

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
ArrowUp / ArrowLeftfocus in thumb, focusable, 与本轴同向往回滚一步(step,默认 40px);交叉轴的那一个不拦,照常交给页面
ArrowDown / ArrowRightfocus in thumb, focusable, 与本轴同向往前滚一步
PageUpfocus in thumb, focusable往回滚一屏(按滚动容器的可视长度)
PageDownfocus in thumb, focusable往前滚一屏
Homefocus in thumb, focusable滚到起点
Endfocus in thumb, focusable滚到终点
Tab / Shift+Tabfocusable滑块是一个 Tab 停靠点;不开 focusable 时整条退出 Tab 序,也对读屏隐藏

ARIA ​

以下属性由 connect 生成。

部件属性值
rootaria-hiddenundefined | 'true'
thumbaria-controlsprops.controls | undefined
thumbaria-disabled'true' | undefined
thumbaria-labelprops.translations.thumb | undefined
thumbaria-orientationprops.orientation | undefined
thumbaria-valuemaxMath.round(max) | undefined
thumbaria-valuemin0 | undefined
thumbaria-valuenowMath.round(metrics.scroll) | undefined
thumbrole'scrollbar' | undefined

样式参考 ​

皮肤 ​

@xihan-ui/styles/scrollbar.css 使用 [data-scope="scrollbar"][data-part="root"] 部件选择器,位于 xihan.components 层。覆盖样式使用 xihan.overrides。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-anchor'layer' | undefined
rootdata-disabled''(条件成立时才出现)
rootdata-dragging''(条件成立时才出现)
rootdata-gutter''(条件成立时才出现)
rootdata-native''(条件成立时才出现)
rootdata-orientationprops.orientation
rootdata-reveal-modeprops.type
rootdata-scrolling''(条件成立时才出现)
rootdata-sizeprops.size
rootdata-state'visible' | 'hidden'
trackdata-disabled''(条件成立时才出现)
trackdata-orientationprops.orientation
thumbdata-disabled''(条件成立时才出现)
thumbdata-dragging''(条件成立时才出现)
thumbdata-orientationprops.orientation
cornerdata-orientationprops.orientation
cornerdata-sizeprops.size
cornerdata-state'visible' | 'hidden'

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-scrollbar-corner-bgcornerbackgrounddefault--xh-scrollbar-track-bgscrollbar 的 corner 部件 background 覆盖槽。
--xh-scrollbar-thumb-bgthumbbackgrounddefault--xh-fg-scrollbar-thumbscrollbar 的 thumb 部件 background 覆盖槽。
--xh-scrollbar-thumb-bg-activethumbbackgrounddragging--xh-fg-scrollbar-thumb-activescrollbar 的 thumb 部件 background 覆盖槽。
--xh-scrollbar-thumb-bg-disabledthumbbackgrounddisabled--xh-border-subtlescrollbar 的 thumb 部件 background 覆盖槽。
--xh-scrollbar-thumb-bg-hoverthumbbackgroundhover--xh-fg-scrollbar-thumb-hoverscrollbar 的 thumb 部件 background 覆盖槽。
--xh-scrollbar-thumb-radiusthumbborder-radiusdefault--xh-shape-pillscrollbar 的 thumb 部件 border-radius 覆盖槽。
--xh-scrollbar-track-bgcorner
track
backgrounddefault--xh-bg-scrollbar-track
transparent
scrollbar 的 corner、track 部件 background 覆盖槽。

动效 ​

background · color · opacity · visibility 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像。

Released under The MIT License