better-scrollbar
better-scrollbar 适配 React/Vue,面向海量数据场景,提供虚拟滚动、自定义滚动条、动态尺寸计算、吸顶分组、底部锚定与长列表渲染能力。
better-scrollbar 最初是 React 自定义滚动条组件,现在更准确的定位是面向复杂数据界面的虚拟化滚动区域系统。当前仓库已经拆成 pnpm/Turborepo monorepo:底层是框架无关的 core,向上提供 React adapter、Vue 3 adapter,同时保留 better-scrollbar 兼容包,让旧用户还能沿用原来的导入路径。
项目定位
这个项目不应该只被描述成“更好看的滚动条”。更准确的说法是:一个可定制滚动容器,内置面向生产复杂场景的虚拟化能力。
滚动区域:提供受控视口、自定义 track/thumb、原生/受控滚动模式,以及横向和纵向滚动状态。
虚拟化内核:把逻辑 item index 映射到像素 offset,控制真实 DOM 数量,并支持动态高度测量后的修正。
交互层:处理 sticky 分组、底部跟随输出、滚动锚点、方向感知 overscan、快速滚动时的 scroll-seek 占位。
框架适配:React 通过组件和 render props 暴露能力,Vue 3 通过组件、slot 和 composable 暴露同一套核心语义。
核心设计
项目的核心是 @better-scrollbar/core 里的 virtual height index。
:: 框架无关的 block index,内部使用 Fenwick tree 记录动态高度差值。固定高度列表走直接数学计算,动态高度列表只维护被测量行的 delta,避免每次滚动扫描全部数据。
:: 测量反馈闭环。React/Vue adapter 先用 estimatedItemHeight 估算总高度,只渲染当前窗口;行挂载后再通过 ResizeObserver、mutation 检查和 offsetHeight 把真实高度写回索引。
:: 逻辑滚动与物理滚动分离。浏览器真实 scroll height 有上限,React adapter 会把超大逻辑滚动范围映射到安全的物理窗口,同时用逻辑 offset 驱动渲染区间。
flowchart LR Input["wheel / drag / scrollTo"] --> State["logical scroll state"] State --> Range["core virtual height index"] Range --> Window["rendered item window"] Window --> Measure["ResizeObserver + mutation checks"] Measure --> Range Range --> Bars["custom track + thumb"]
项目亮点
能力 | 设计选择 | 价值 |
|---|---|---|
大列表 |
| 逻辑上可以表达百万级甚至更大数据量,真实 DOM 数量仍然受控。 |
动态高度 | 默认 50,000 条的测量高度缓存 | 真实高度逐步修正估算模型,同时避免无限缓存。 |
sticky 分组 |
| 分组列表、日志段落、业务 section 可以在滚动中保持上下文。 |
流式输出 |
| 聊天、日志、Agent 输出可以自动贴底,同时保留用户主动向上滚动的意图。 |
快速滚动 |
| 高速滚动时先渲染低成本占位,降低昂贵 row renderer 的压力。 |
定制视觉 | React render props / Vue slots | 产品可以替换 view、track、thumb,而不需要 fork 滚动逻辑。 |
包结构
@better-scrollbar/core:算法、共享类型、虚拟高度索引、overscan 工具、sticky 工具、浏览器 scroll height 安全处理。@better-scrollbar/react:ScrollBar组件、ref API、render props、动态测量、可访问性元数据、sticky overlay 和自定义滚动条组装。@better-scrollbar/vue:BScrollBar、scoped slot、composable、暴露式 scroll 方法,并复用同一套 core index。better-scrollbar:兼容包,继续导出 React adapter,降低旧用户迁移成本。
架构判断
项目最值得保留的边界是:核心数学不依赖 React 或 Vue;adapter 只负责生命周期、DOM 测量、事件、渲染和框架风格 API。
这个边界让项目的性能叙事更可信。range 计算、动态高度更新、sticky 计算、滚动窗口映射可以分别被测试;React/Vue 层则专注验证用户能看到的交互结果。
适合场景
大表格、日志、trace、时间线等需要穿越超大逻辑数据集的界面。
设计系统需要品牌化滚动条,但又不能放弃可访问性和可控滚动状态。
聊天、Agent 输出、构建日志这类需要“贴底但不打断用户阅读”的流式区域。
需要 sticky header、分组列表、动态高度行的复杂业务列表。
开源信号
TypeScript 优先,包导出、peer dependency、兼容包边界都比较清晰。
monorepo 把 core 算法和框架 adapter 拆开,便于后续扩展其他运行时。
测试覆盖 virtual range、包导出、React 行为和 Vue 包形态。
README、API 文档和 demo site 可以共同支撑“虚拟化滚动区域”的产品叙事。
后续压力点
站点表达应继续聚焦“virtualized scroll area”,不要退回“只是自定义滚动条”的窄定位。
极限性能数据要继续用固定 benchmark contract 描述,避免把本地测量泛化成所有浏览器场景。
首页首屏 API 应降低噪音,把第一学习路径收敛到
itemCount、renderItem、estimatedItemHeight、height、overscan和滚动条定制。