基于 Base UI 的滚动容器:真正滚动的是视口,滚动条渲染成视口的 兄弟节点(覆盖式,不占布局宽度)。这个结构是它存在的理由 —— 库里的 scroll-fade 渐隐是挂在滚动元素上的 mask,原生滚动条长在滚动元素 内部会被 mask 一起压暗,兄弟滚动条则始终清晰。
库内的 DataTable、 InfiniteSelect 以及本站 demo 卡片的代码区,滚动都走同一个 ScrollArea。
使用
import { ScrollArea } from '@gedatou/cadenza-ui'<ScrollArea className="rounded-xl border block-64 inline-72">
{/* 会溢出的内容 */}
</ScrollArea>给根元素定尺寸即可,视口自动撑满。默认纵向、滚动条 hover 显示 —— 两件事各有一个 prop:方向与显隐。
组成
一个 ScrollArea 展开是四个部件,只有滚动条另外对外导出:
ScrollArea ← 根:尺寸约束定在这里,它自己不滚动
├── viewport ← 真正滚动的元素(viewportClassName / viewportRef 指的就是它)
├── ScrollAreaScrollbar ← 视口的兄弟,覆盖式;按 orientation 渲染 1–2 条
│ └── thumb
└── corner ← 两条滚动条交汇处的小方块viewport / thumb / corner 由封装层按 orientation 与 scrollbars 自动渲染,
外部通过 viewportClassName 和 data-slot 触达。
单独导出的 ScrollAreaScrollbar 供自定义组合场景使用,一般用不到 —— 名字随
家族(Base UI 的部件就叫 ScrollArea.Scrollbar),不是 shadcn 的裸名 ScrollBar。
它自己不带悬停淡出:那身类名是 ScrollArea 按 scrollbars 传进去的。
方向
orientation 决定渲染哪些滚动条:vertical(默认)只出纵向、horizontal
只出横向、both 两条都要。横向滚动时内容要用 inline-max 之类按内容撑开:
滚动条显隐
scrollbars 三档:always 常显、hover(默认)悬停或滚动进行中显示、
hidden 不渲染:
无溢出时 Base UI 会直接把滚动条从 DOM 卸载(keepMounted 默认 false),
不用自己判断。hover 档不靠卸载,而是把滚动条压成 opacity-0,由
data-hovering / data-scrolling 提回不透明 —— 透明的条也不会挡住点击,
因为 data-hovering 只在指针进到区域内时存在,那正是它不透明的时候。
滚动渐隐
把 scroll-fade 工具类挂到视口上(viewportClassName,不要挂根元素):
scroll-fade-y 纵向、scroll-fade-x 横向、scroll-fade-inset 双轴并支持
固定表头 / 固定列偏移。渐隐随滚动位置显隐 —— 滚到头对应边的 fade 自动消失,
这一步靠 animation-timeline: scroll(self),只有元素自己在滚动时才有进度:
挂到根元素上既拿不到进度,又会把兄弟滚动条一起压暗,等于退回原生滚动条的处境。
不支持 scroll-driven animation 的浏览器退化成两端常显渐隐。
尺寸用 --scroll-fade-size(或 scroll-fade-8 这类工具类)调,
详见 @gedatou/cadenza-ui/styles.css 里的 scroll-fade 一族。
状态与 className
className 一律双形态:字符串,或 (state) => string 的函数。下表左列是挂在 DOM 上的
data-*,Tailwind 直接当变体写(data-scrolling:opacity-100);右列是同一个状态在
函数 className 里的名字。
className(根)与 viewportClassName 收到的是完全同一组字段——视口的 state 就是
根的 state(ScrollAreaViewportState extends ScrollAreaRootState),两边都含
cornerHidden(角落方块是否隐藏,没有对应的 data-*)。hovering 与 orientation
只在滚动条元素上:想按悬停改根元素的样子,用 hover: 伪类。
需要从外部定位时用 data-slot:
键盘交互
滚动本身是浏览器给可聚焦滚动容器的原生行为。这里只有两件事是组件做的:
Base UI 让有溢出的视口可聚焦(否则纯键盘用户到不了滚动区域),封装层给它
focus-visible 的 ring。
Props
顺序规则:必填 → 非受控默认值 → 受控值 → 回调 → 行为开关 → 外观 → className。
三个类型一并导出:ScrollAreaProps(根组件完整 props:Base UI Root 的 props +
上表的 seam 扩展)/ ScrollAreaScrollbarProps(滚动条部件的 props,即
ScrollArea.Scrollbar.Props)/ ScrollAreaScrollbars(scrollbars 的取值联合)。