Skip to content
OverlayScrollbars

OverlayScrollbars

一个 JavaScript 滚动条插件,可以隐藏原生滚动条,提供可自定义样式的覆盖滚动条,并保留原生功能和体验。

为什么?

我创建这个插件是因为我讨厌丑陋且占用空间的滚动条。类似的插件在功能、质量、简洁性、许可或浏览器支持方面都未能满足我的要求。

目标与功能

  • 简单、强大且文档齐全的 API。
  • 高浏览器兼容性 - Firefox 59+Chrome 55+Opera 42+Edge 15+Safari 10+
  • 完全可访问 - 完全保留原生滚动行为。
  • 可以在服务器上运行(NodeDenoBun)- 支持 SSRSSGISR
  • 在各种设备上测试过 - 移动设备桌面设备平板设备
  • 测试过各种(和混合)输入 - 鼠标触摸
  • 树摇 - 仅打包你真正需要的部分。
  • 自动更新检测 - 无需轮询
  • 利用最新的浏览器功能 - 在新浏览器中提供最佳性能。
  • 流程独立 - 支持所有 directionflex-directionwriting-mode 的值。
  • 支持滚动捕捉。
  • 支持所有 虚拟滚动 库。
  • 支持 body 元素。
  • 简单且有效的滚动条样式。
  • 高度可定制。
  • TypeScript 支持 - 完全用 TypeScript 编写。
  • 无依赖 - 100% 自编写以确保小体积和最佳功能。
  • 高质量且完全类型化的框架版本,适用于 reactvueangularsveltesolid

选择你的框架

除了原生 JavaScript 版本,你还可以使用官方框架组件和工具:

ReactVueAngularSvelteSolid

入门

npm 和 nodejs

OverlayScrollbars 可以从 npm 或你选择的包管理器下载:

sh
npm install overlayscrollbars

安装后,可以导入:

js
import "overlayscrollbars/overlayscrollbars.css";
import {
  OverlayScrollbars,
  ScrollbarsHidingPlugin,
  SizeObserverPlugin,
  ClickScrollPlugin,
} from "overlayscrollbars";

注意:如果路径 'overlayscrollbars/overlayscrollbars.css' 无法使用,请使用 'overlayscrollbars/styles/overlayscrollbars.css' 作为 CSS 文件的导入路径。

您可以使用这个 Node 示例 作为参考或起点。

手动下载和嵌入

您可以在不使用任何打包工具或包管理器的情况下使用 OverlayScrollbars。
只需下载其中一个 发布版本 或使用 CDN

  • 使用带有 .browser 扩展名的 JavaScript 文件。
  • 如果需要支持旧版浏览器,请使用带有 .es5 扩展名的 JavaScript 文件,否则使用 .es6 文件。
  • 对于生产环境,使用带有 .min 扩展名的 JavaScript / 样式表文件。

在您的 HTML 中手动嵌入 OverlayScrollbars:

html
<link type="text/css" href="path/to/overlayscrollbars.css" rel="stylesheet" />
<script
  type="text/javascript"
  src="path/to/overlayscrollbars.browser.es.js"
  defer
></script>

使用全局变量 OverlayScrollbarsGlobal 来访问 API,类似于在 nodejs / 模块中使用:

js
var {
  OverlayScrollbars,
  ScrollbarsHidingPlugin,
  SizeObserverPlugin,
  ClickScrollPlugin,
} = OverlayScrollbarsGlobal;

您可以使用这个 浏览器示例 作为参考或起点。

本文档中的示例使用 import 语法,而不是 OverlayScrollbarsGlobal 对象。然而,两种版本是等价的。

初始化

OverlayScrollbars 的初始化是针对 每个元素 显式进行的。只有在插件初始化的元素上的滚动条会被更改。子元素的滚动条将保持不变,除非插件也在它们上面初始化。

您可以直接使用 ElementObject 初始化一个新实例,这样可以更好地控制初始化过程。

js
// 使用元素进行简单初始化
const osInstance = OverlayScrollbars(document.querySelector("#myElement"), {});

解决初始化闪烁问题

当你初始化 OverlayScrollbars 时,需要几毫秒的时间来创建并将所有元素附加到 DOM。在此期间,原生滚动条仍然可见,并将在初始化完成后被替换掉。这被视为闪烁。

要解决此行为,请将 data-overlayscrollbars-initialize 属性应用于目标元素(在为 body 元素初始化滚动条时,也应用于 html 元素)。

html
<!-- 针对 body 元素 -->
<html data-overlayscrollbars-initialize>
  <head></head>
  <body data-overlayscrollbars-initialize></body>
</html>

<!-- 针对所有其他元素 -->
<div data-overlayscrollbars-initialize>OverlayScrollbars 应用于此 div</div>

使用对象进行初始化

Details 这是一个深入的话题。点击这里阅读。

唯一必需的字段是 target 字段。这是插件将应用的字段。
如果你仅使用 target 字段进行对象初始化,结果等同于元素初始化:

js
// 两种初始化方式的结果相同

OverlayScrollbars(document.querySelector('#myElement'), {});
OverlayScrollbars({ target: document.querySelector('#myElement') }, {});

使用对象初始化时,你可以指定库如何处理生成的元素。 例如,你可以指定一个现有元素作为 viewport 元素。然后库将不会生成它,而是使用指定的元素:

js
OverlayScrollbars({
 target: document.querySelector('#target'),
 elements: {
   viewport: document.querySelector('#viewport'),
 },
}, {});

如果你有一个固定的 DOM 结构并且不希望 OverlayScrollbars 创建自己的元素,这非常有用。当你希望另一个库与 OverlayScrollbars 一起工作时,这种情况非常常见。


你还可以决定滚动条应该应用到哪个元素:

js
OverlayScrollbars(
  {
    target: document.querySelector("#target"),
    scrollbars: {
      slot: document.querySelector("#target").parentElement,
    },
  },
  {}
);

最后但同样重要的是,您可以决定何时取消初始化:

js
OverlayScrollbars(
  {
    target: document.querySelector("#target"),
    cancel: {
      nativeScrollbarsOverlaid: true,
      body: null,
    },
  },
  {}
);

在上述示例中,如果原生滚动条被覆盖,或者如果您的目标是一个 body 元素且插件已确定初始化到 body 元素会干扰原生功能(如 window.scrollTo),则初始化将被中止。

选项

您可以使用一组初始选项初始化 OverlayScrollbars,并可以随时通过 options 方法更改这些选项:

js
OverlayScrollbars(document.querySelector("#myElement"), {
  overflow: {
    x: "hidden",
  },
});

深入了解选项

这是一个深入的话题。点击这里阅读。

默认选项为:

js
const defaultOptions = {
  paddingAbsolute: false,
  showNativeOverlaidScrollbars: false,
  update: {
    elementEvents: [["img", "load"]],
    debounce: [0, 33],
    attributes: null,
    ignoreMutation: null,
  },
  overflow: {
    x: "scroll",
    y: "scroll",
  },
  scrollbars: {
    theme: "os-theme-dark",
    visibility: "auto",
    autoHide: "never",
    autoHideDelay: 1300,
    autoHideSuspend: false,
    dragScroll: true,
    clickScroll: false,
    pointers: ["mouse", "touch", "pen"],
  },
};

paddingAbsolute

类型默认值
booleanfalse

指示内容的填充是否应为绝对值。

showNativeOverlaidScrollbars

类型默认值
booleanfalse

指示是否应显示原生覆盖的滚动条。

update.elementEvents

类型默认值
Array<[string, string]> | null[['img', 'load']]

一个元组数组。元组中的第一个值是一个 selector,第二个值是 event names。如果具有指定选择器的任何元素发出任何指定事件,插件将更新自身。默认值可以解释为“如果任何 img 元素发出 load 事件,插件将更新自身。”

update.debounce

类型默认值
[number, number] | number | null[0, 33]

注意:如果超时使用 0,将使用 requestAnimationFrame 而不是 setTimeout 进行防抖。

对跟踪内容更改的 MutationObserver 进行防抖。如果传递 元组,第一个值是超时,第二个是最大等待时间。如果只有一个 数字,则被视为超时,没有最大等待时间。使用 null 则没有防抖。用于微调性能。

update.attributes

类型默认值
string[] | nullnull

注意:即使此选项为 nullMutationObserver 也始终观察一组基本属性。

MutationObserver 应观察内容的其他属性数组。

update.ignoreMutation

类型默认值
((mutation) => any) | nullnull

一个函数,它接收一个 MutationRecord 作为参数。如果函数返回一个真值,则忽略该变异,插件不会更新。用于微调性能。

overflow.x

类型默认值
string'scroll'

注意:有效值为:'hidden''scroll''visible''visible-hidden''visible-scroll'

水平(x)轴的溢出行为。

overflow.y

类型默认值
string'scroll'

注意:有效值为:'hidden''scroll''visible''visible-hidden''visible-scroll'

垂直(y)轴的溢出行为。

scrollbars.theme

类型默认值
string | null'os-theme-dark'

将指定的主题(类名)应用于滚动条。

scrollbars.visibility

类型默认值
string'auto'

注意:有效值为:'visible''hidden''auto'

如果滚动轴能够具有可滚动溢出,则滚动条的可见性。(轴的可滚动溢出仅在溢出行为设置为 'scroll''visible-scroll' 时可能。)

scrollbars.autoHide

类型默认值
string'never'

注意:有效值为:'never''scroll''leave''move'

指示是否在某些用户操作后自动隐藏可见滚动条。

scrollbars.autoHideDelay

类型默认值
number1300

滚动条自动隐藏前的延迟时间(毫秒)。

scrollbars.autoHideSuspend

类型默认值
booleanfalse

暂停 autoHide 功能,直到执行第一次滚动交互。
此选项的默认值为 false,以保持向后兼容性,但建议设置为 true 以提高可访问性。

scrollbars.dragScroll

类型默认值
booleantrue

指示是否可以拖动滚动条手柄进行滚动。

scrollbars.clickScroll

类型默认值
boolean | 'instant'false

注意:如果设置为 true,则需要 ClickScrollPlugin

指示是否可以点击滚动条轨道进行滚动。

scrollbars.pointers

类型默认值
string[] | null['mouse', 'touch', 'pen']

插件应响应的 PointerTypes

TypeScript

ts
// OverlayScrollbars 实例的选项。
type Options = {
  // 填充是否应为绝对值。
  paddingAbsolute: boolean;
  // 是否显示原生滚动条。仅在原生滚动条被覆盖时有效。
  showNativeOverlaidScrollbars: boolean;
  // 自定义自动更新行为。
  update: {
    /**
     * 来自具有给定选择器的元素的给定事件将触发更新。
     * 对于 MutationObserver 和 ResizeObserver 无法检测到的内容非常有用
     * 例如:图像的 `load` 事件或 `transitionend` / `animationend` 事件。
     */
    elementEvents: Array<[elementSelector: string, eventNames: string]> | null;
    /**
     * 用于检测内容更改的防抖。
     * 如果提供了元组,您可以自定义 `timeout` 和 `maxWait`(以毫秒为单位)。
     * 如果是单个数字,则仅自定义 `timeout`。
     *
     * 如果 `timeout` 为 `0`,仍然存在防抖(通过 `requestAnimationFrame` 而不是 `setTimeout` 完成)。
     */
    debounce: [timeout: number, maxWait: number] | number | null;
    /**
     * 如果更改了 HTML 属性,将触发更新。
     * 基本属性如 `id`、`class`、`style` 等始终被观察,不必显式添加。
     */
    attributes: string[] | null;
    // 一个函数,使得可以忽略内容变异或为 null 如果不应忽略任何内容。
    ignoreMutation: ((mutation: MutationRecord) => any) | null;
  };
  // 自定义每个轴的溢出行为。
  overflow: {
    // 水平(x)轴的溢出行为。
    x: OverflowBehavior;
    // 垂直(y)轴的溢出行为。
    y: OverflowBehavior;
  };
  // 自定义滚动条的外观。
  scrollbars: {
    // 滚动条的主题。主题值将作为 `class` 添加到实例的所有 `scrollbar` 元素。
    theme: string | null;
    // 滚动条的可见性行为。
    visibility: ScrollbarsVisibilityBehavior;
    // 滚动条的自动隐藏行为。
    autoHide: ScrollbarsAutoHideBehavior;
    // 滚动条的自动隐藏延迟(以毫秒为单位)。
    autoHideDelay: number;
    // 滚动条的自动隐藏行为是否暂停,直到发生滚动。
    autoHideSuspend: boolean;
    // 是否可以拖动滚动条的手柄以滚动视口。
    dragScroll: boolean;
    // 是否可以点击滚动条的轨道以滚动视口。
    clickScroll: ScrollbarsClickScrollBehavior;
    // 支持的指针类型数组。
    pointers: string[] | null;
  };
};
markdown
// 轴的溢出行为。
type OverflowBehavior =
// 无法滚动,内容被裁剪。
| 'hidden'
// 无法滚动,内容不被裁剪。
| 'visible'
// 如果有溢出,可以滚动。
| 'scroll'
/\*\*

- 如果另一个轴没有溢出,行为类似于 `visible`
- 如果另一个轴有溢出,行为类似于 `hidden`
  \*/
  | 'visible-hidden'
  /\*\*
- 如果另一个轴没有溢出,行为类似于 `visible`
- 如果另一个轴有溢出,行为类似于 `scroll`
  \*/
  | 'visible-scroll';

// 滚动条的可见性行为。
type ScrollbarsVisibilityBehavior =
// 滚动条始终可见。
| 'visible'
// 滚动条始终隐藏。
| 'hidden'
// 只有在有溢出时滚动条才可见。
| 'auto';

// 滚动条自动隐藏行为
type ScrollbarsAutoHideBehavior =
// 滚动条从不自动隐藏。
| 'never'
// 除非用户滚动,否则滚动条隐藏。
| 'scroll'
// 除非指针在主机元素中移动或用户滚动,否则滚动条隐藏。
| 'move'
// 如果指针离开主机元素或除非用户滚动,否则滚动条隐藏。
| 'leave';

// 滚动条点击滚动行为。
type ScrollbarsClickScrollBehavior = boolean | 'instant';

事件

您可以使用一组初始事件初始化 OverlayScrollbars,可以随时通过 onoff 方法进行管理:

js
OverlayScrollbars(
  document.querySelector("#myElement"),
  {},
  {
    updated(osInstance, onUpdatedArgs) {
      // ...
    },
  }
);

深入了解事件

这是一个深入的话题。点击这里阅读。

注意:每个事件都会接收从中调度的 instance 作为第一个参数。始终如此。

initialized

参数描述
instance调度事件的实例。

在所有生成的元素、观察者和事件被附加到 DOM 后调度。

updated

参数描述
instance调度事件的实例。
onUpdatedArgs一个详细描述更新的 object

注意:如果触发了更新但没有任何变化,则不会调度事件。

在实例更新后调度。

destroyed

参数描述
instance调度事件的实例。
canceled一个 boolean,指示初始化是否被取消并因此被销毁。

在所有生成的元素、观察者和事件从 DOM 中移除后调度。

scroll

参数描述
instance调度事件的实例。
eventDOM 事件的原始 event 参数。

通过滚动视口调度。

TypeScript

ts
// 事件名称与其监听器参数之间的映射。
type EventListenerArgs = {
  // 在所有元素初始化并附加后调度。
  initialized: [instance: OverlayScrollbars];
  // 在更新后调度。
  updated: [
    instance: OverlayScrollbars,
    onUpdatedArgs: OnUpdatedEventListenerArgs
  ];
  // 在所有元素、观察者和事件被销毁后调度。
  destroyed: [instance: OverlayScrollbars, canceled: boolean];
  // 在滚动时调度。
  scroll: [instance: OverlayScrollbars, event: Event];
};
markdown
interface OnUpdatedEventListenerArgs {
// 描述 DOM 中更改内容的提示。
updateHints: {
// 主机元素的大小是否发生了变化。
sizeChanged: boolean;
// 主机元素的方向是否发生了变化。
directionChanged: boolean;
// 内在高度行为是否发生了变化。
heightIntrinsicChanged: boolean;
// 视口元素的溢出边缘(clientWidth / clientHeight)是否发生了变化。
overflowEdgeChanged: boolean;
// 溢出量是否发生了变化。
overflowAmountChanged: boolean;
// 溢出样式是否发生了变化。
overflowStyleChanged: boolean;
// 滚动坐标是否发生了变化。
scrollCoordinatesChanged: boolean;
// 是否发生了主机突变。
hostMutation: boolean;
// 是否发生了内容突变。
contentMutation: boolean;
};
// 更改的选项。
changedOptions: PartialOptions;
// 更新是否在强制无效缓存的情况下发生。
force: boolean;
}

实例

可以通过调用 OverlayScrollbars 函数并传入一个元素和选项对象来创建 OverlayScrollbars 实例。

js
const osInstance = OverlayScrollbars(document.body, {});

实例方法

这是一个深入的话题。点击这里阅读。

options(): Options

获取实例的当前选项。

返回值描述
Options当前选项。

options(newOptions, pure?): Options

设置实例的当前选项。

参数类型描述
newOptionsPartialOptions应用的新(部分)选项。
pureboolean | undefined在添加新选项之前是否重置选项。
返回值描述
Options完整的新选项。

on(eventListeners, pure?): Function

向实例添加事件监听器。

参数类型描述
eventListenersEventListeners包含添加的监听器的对象。字段是事件名称和监听器。
pureboolean | undefined在添加新监听器之前是否移除所有已添加的事件监听器。
返回值描述
Function移除所有添加的事件监听器的函数。

on(name, listener): Function

向实例添加单个事件监听器。

参数类型描述
namestring事件名称。
listenerFunction事件分派时调用的函数。
返回值描述
Function移除添加的事件监听器的函数。

on(name, listeners): Function

向实例添加多个事件监听器。

参数类型描述
namestring事件名称。
listenersFunction[]事件分派时调用的函数。
返回值描述
Function移除添加的事件监听器的函数。

off(name, listener): void

从实例中移除单个事件监听器。

参数类型描述
namestring事件名称。
listenerFunction要移除的函数。

off(name, listeners): void

从实例中移除多个事件监听器。

参数类型描述
namestring事件名称。
listenersFunction[]要移除的函数。

update(force?): boolean

更新实例。

参数类型描述
forceboolean | undefined是否强制使缓存无效。
返回值描述
Function一个布尔值,指示是否通过此更新触发了 update 事件。

state(): State

获取实例的状态。

返回值描述
State描述实例状态的对象。

elements(): Elements

获取实例的元素。

返回值描述
Elements描述实例元素的对象。

destroy(): void

销毁实例并移除所有添加的元素。

plugin(plugin: object): object | undefined

获取传入插件的实例模块实例。

返回值描述
object | undefined描述插件实例模块实例的对象,如果未找到实例则为 undefined

TypeScript

ts
// OverlayScrollbars TypeScript 接口的简化版本。
interface OverlayScrollbars {
  // 获取实例的当前选项。
  options(): Options;
  // 设置实例的当前选项。
  options(newOptions: PartialOptions, pure?: boolean): Options;

  // 向实例添加事件监听器。
  on(eventListeners: EventListeners, pure?: boolean): () => void;
  // 向实例添加单个事件监听器。
  on<N extends keyof EventListenerArgs>(
    name: N,
    listener: EventListener<N>
  ): () => void;
  // 向实例添加多个事件监听器。
  on<N extends keyof EventListenerArgs>(
    name: N,
    listener: EventListener<N>[]
  ): () => void;

  // 从实例中移除单个事件监听器。
  off<N extends keyof EventListenerArgs>(
    name: N,
    listener: EventListener<N>
  ): void;
  // 从实例中移除多个事件监听器。
  off<N extends keyof EventListenerArgs>(
    name: N,
    listener: EventListener<N>[]
  ): void;

  // 更新实例。
  update(force?: boolean): boolean;

  // 获取实例的状态。
  state(): State;

  // 获取实例的元素。
  elements(): Elements;

  // 销毁实例并移除所有添加的元素。
  destroy(): void;

  // 获取传入插件的实例模块实例。
  plugin<P extends InstancePlugin>(
    osPlugin: P
  ): InferInstancePluginModuleInstance<P> | undefined;
}

// 描述 OverlayScrollbars 实例的状态。
interface State {
  // 描述当前的像素填充。
  padding: TRBL;
  // 当前填充是否为绝对值。
  paddingAbsolute: boolean;
  // 视口的客户端宽度(x)和高度(y),以像素为单位。
  overflowEdge: XY<number>;
  // 溢出量,以像素为单位。
  overflowAmount: XY<number>;
  // 视口的 CSS 溢出样式。
  overflowStyle: XY<OverflowStyle>;
  // 视口是否有溢出。
  hasOverflow: XY<boolean>;
  // 视口的滚动坐标。
  scrollCoordinates: {
    // 每个轴的起始(原点)滚动坐标。
    start: XY<number>;
    // 每个轴的结束滚动坐标。
    end: XY<number>;
  };
  // 方向是否被认为是 rtl。
  directionRTL: boolean;
  // 实例是否被认为已销毁。
  destroyed: boolean;
}

// 描述 OverlayScrollbars 实例的元素。
interface Elements {
  // 应用实例的元素。
  target: HTMLElement;
  // 主机元素。它是所有其他元素的根。
  host: HTMLElement;
  /**
   * 负责正确填充的元素。
   * 根据初始化,它可以与视口元素相同。
   */
  padding: HTMLElement;
  // 负责滚动的元素。
  viewport: HTMLElement;
  /**
   * 负责保存实际内容的元素。
   * 根据初始化,它可以与视口元素相同。
   */
  content: HTMLElement;
  /**
   * 可以通过它获取当前 `scrollLeft` 或 `scrollTop` 偏移量的元素。
   * 根据目标元素,它可以与视口元素相同。
   */
  scrollOffsetElement: HTMLElement;
  /**
   * 可以通过它添加 `scroll` 事件的元素。
   * 根据目标元素,它可以与视口元素相同。
   */
  scrollEventElement: HTMLElement | Document;
  // 水平滚动条的元素。
  scrollbarHorizontal: CloneableScrollbarElements;
  // 垂直滚动条的元素。
  scrollbarVertical: CloneableScrollbarElements;
}

静态对象

静态 OverlayScrollbars 对象。

js
OverlayScrollbars.plugin(SomePlugin);

静态对象方法

这是一个深入的话题。点击这里阅读。

valid(osInstance): boolean

检查传入的值是否为有效且未销毁的 overlayscrollbars 实例

参数类型描述
osInstanceany要检查的值。
返回值描述
boolean传入的值是否为有效且未销毁的 overlayscrollbars 实例。

env(): Environment

获取环境。

返回值描述
Environment描述环境的对象。

nonce(newNonce): void

为内联样式设置 nonce 属性。

参数类型描述
newNoncestring | undefined内联样式的 nonce 属性。

plugin(plugin): object | undefined

添加单个插件。

参数类型描述
pluginobject要添加的插件。
返回值描述
object | void描述插件静态模块实例的对象,如果未找到实例则为 void

plugin(plugins): (object | void)[]

添加多个插件。

参数类型描述
pluginsobject[]要添加的插件。
返回值描述
(object | void)[]描述插件静态模块实例的数组,如果未找到实例则为 undefined

TypeScript

ts
// OverlayScrollbars 静态对象。
interface OverlayScrollbarsStatic {
  // 获取传入目标的实例或 `undefined` 如果目标没有实例。
  (target: InitializationTarget): OverlayScrollbars | undefined;
  // 使用传入的选项和事件监听器初始化传入目标的 OverlayScrollbars。
  (
    target: InitializationTarget,
    options: PartialOptions,
    eventListeners?: EventListeners
  ): OverlayScrollbars;

  // 检查传入的值是否为有效且未销毁的 overlayscrollbars 实例。
  valid(osInstance: any): osInstance is OverlayScrollbars;

  // 获取环境。
  env(): Environment;

  // 为内联样式设置 nonce 属性。
  nonce(newNonce: string | undefined): void;

  // 添加单个插件。
  plugin(plugin: Plugin): InferStaticPluginModuleInstance<Plugin>;
  // 添加多个插件。
  plugin(plugins: Plugin[]): InferStaticPluginModuleInstance<Plugin>[];
}

// 描述 OverlayScrollbars 环境。
interface Environment {
  // 浏览器/系统的原生滚动条大小。
  scrollbarsSize: XY<number>;
  // 原生滚动条是否被覆盖。
  scrollbarsOverlaid: XY<boolean>;
  // 浏览器是否支持原生滚动条隐藏。
  scrollbarsHiding: boolean;
  // 浏览器是否支持 ScrollTimeline API。
  scrollTimeline: boolean;
  // 如果没有其他指定,则使用的默认初始化。
  staticDefaultInitialization: Initialization;
  // 如果没有其他指定,则使用的默认选项。
  staticDefaultOptions: Options;

  // 返回当前默认初始化。
  getDefaultInitialization(): Initialization;
  // 返回当前默认选项。
  getDefaultOptions(): Options;

  /**
   * 设置新的默认初始化。
   * 如果新的默认初始化部分填充,则与当前默认初始化深度合并。
   * @param newDefaultInitialization 新的默认初始化。
   * @returns 当前默认初始化。
   */
  setDefaultInitialization(
    newDefaultInitialization: PartialInitialization
  ): Initialization;
  /**
   * 设置新的默认选项。
   * 如果新的默认选项部分填充,则与当前默认选项深度合并。
   * @param newDefaultOptions 新的默认选项。
   * @returns 当前默认选项。
   */
  setDefaultOptions(newDefaultOptions: PartialOptions): Options;
}

样式

OverlayScrollbars 提供了两个主题,分别是 os-theme-darkos-theme-light。您可以使用 scrollbars.theme 选项来更改主题。

自定义主题可以通过多种方式完成。最简单和最快的方法是使用预定义的 CSS 自定义属性,也称为 CSS 变量。如果这还不够,您可以添加自定义类名或为现有类名添加自定义样式。

深入样式

这是一个深入的话题。点击这里阅读。

CSS 自定义属性

OverlayScrollbars 提供了一组 CSS 自定义属性,使滚动条样式变得简单快捷:

scss
.os-scrollbar {
  // 滚动条的大小
  --os-size: 0;
  // 滚动条的轴垂直填充(水平:padding-y,垂直:padding-x)
  --os-padding-perpendicular: 0;
  // 滚动条的轴填充(水平:padding-x,垂直:padding-y)
  --os-padding-axis: 0;
  // 滚动条轨道的边框半径
  --os-track-border-radius: 0;
  // 滚动条轨道的背景
  --os-track-bg: none;
  // 滚动条轨道的 :hover 背景
  --os-track-bg-hover: none;
  // 滚动条轨道的 :active 背景
  --os-track-bg-active: none;
  // 滚动条轨道的边框
  --os-track-border: none;
  // 滚动条轨道的 :hover 边框
  --os-track-border-hover: none;
  // 滚动条轨道的 :active 边框
  --os-track-border-active: none;
  // 滚动条手柄的边框半径
  --os-handle-border-radius: 0;
  // 滚动条手柄的背景
  --os-handle-bg: none;
  // 滚动条手柄的 :hover 背景
  --os-handle-bg-hover: none;
  // 滚动条手柄的 :active 背景
  --os-handle-bg-active: none;
  // 滚动条手柄的边框
  --os-handle-border: none;
  // 滚动条手柄的 :hover 边框
  --os-handle-border-hover: none;
  // 滚动条手柄的 :active 边框
  --os-handle-border-active: none;
  // 滚动条手柄的最小大小
  --os-handle-min-size: 33px;
  // 滚动条手柄的最大大小
  --os-handle-max-size: none;
  // 滚动条手柄的轴垂直大小(水平:高度,垂直:宽度)
  --os-handle-perpendicular-size: 100%;
  // 滚动条手柄的 :hover 轴垂直大小(水平:高度,垂直:宽度)
  --os-handle-perpendicular-size-hover: 100%;
  // 滚动条手柄的 :active 轴垂直大小(水平:高度,垂直:宽度)
  --os-handle-perpendicular-size-active: 100%;
  // 增加滚动条手柄的交互区域。
  --os-handle-interactive-area-offset: 0;
}

您可以同时更改两个滚动条的属性,也可以为每个滚动条轴更改属性。在下面的示例中,我选择了 os-theme-custom 作为主题名称:

scss
// 水平和垂直滚动条为 10px
.os-theme-custom {
  --os-size: 10px;
}

// 水平滚动条为 10px
.os-theme-custom.os-scrollbar-horizontal {
  --os-size: 10px;
}
// 垂直滚动条为 20px
.os-theme-custom.os-scrollbar-vertical {
  --os-size: 20px;
}

然后,您可以通过 scrollbars.theme 选项分配您的主题:

js
OverlayScrollbars(document.body, {
  scrollbars: {
    theme: "os-theme-custom",
  },
});

由于滚动条样式通常很简单,这组选项应该足以获得您想要的样式。 如果您需要更多的自由,您可以通过向下节中描述的基本类名添加样式来创建自己的样式。

滚动条结构和 CSS 类名

滚动条的 HTML 标记如下所示:

html
<div class="os-scrollbar os-scrollbar-horizontal">
  <div class="os-scrollbar-track">
    <div class="os-scrollbar-handle"></div>
  </div>
</div>
<div class="os-scrollbar os-scrollbar-vertical">
  <div class="os-scrollbar-track">
    <div class="os-scrollbar-handle"></div>
  </div>
</div>

类名是简化的,在实际应用中,.os-scrollbar 元素可以有其他类名来修改外观(主要是可见性和对齐)。

下面是您将遇到的最重要类名的列表:

CSS 类名描述
.os-scrollbar滚动条的根元素。
.os-scrollbar-rtl指示滚动条所属的主机元素的 RTL 方向。
.os-scrollbar-horizontal水平滚动条的根元素。
.os-scrollbar-vertical垂直滚动条的根元素。
.os-scrollbar-handle-interactive指示滚动条内的手柄是交互式的(scrollbars.dragScroll 不是 false)。
.os-scrollbar-track-interactive指示滚动条内的轨道是交互式的(scrollbars.clickScroll 不是 false)。
.os-scrollbar-track轨道元素。这是嵌套手柄元素的轨道。如果 scrollbars.clickScroll 不是 false,这是用户可以点击以更改滚动偏移量的元素。
.os-scrollbar-handle手柄元素。如果 scrollbars.dragScroll 不是 false,这是用户可以拖动以更改滚动偏移量的手柄。

如果您创建自己的主题,请仅使用上面列出的类。所有其他类都是用于更改滚动条的可见性、对齐和指针事件的修饰类。

注意事项

您 CSS 文件中选择的主题类名必须与选项中分配的主题名称匹配。如果 CSS 类名是 .my-theme,则 scrollbars.theme 必须是 'my-theme'

请注意您的堆栈。例如,css-modules 会更改您的类名以避免命名冲突。始终检查您的 CSS 是否符合预期。

插件

任何不被视为核心功能或旧浏览器兼容性的内容都通过插件公开。这是因为所有未使用的插件在树形抖动期间都会被省略,不会出现在您的最终包中。OverlayScrollbars 附带以下插件:

使用插件

插件的使用方式如下:

ts
import {
  OverlayScrollbars,
  ScrollbarsHidingPlugin,
  SizeObserverPlugin,
  ClickScrollPlugin,
} from "overlayscrollbars";
markdown
// 单个插件
OverlayScrollbars.plugin(ScrollbarsHidingPlugin);

// 多个插件
OverlayScrollbars.plugin([SizeObserverPlugin, ClickScrollPlugin]);

深入了解插件

这是一个深入的话题。点击这里阅读。

插件是具有单个字段的普通对象,字段的名称就是插件的名称。这个名称是插件的标识符,必须在所有插件中唯一。如果多个插件具有相同的名称,最后添加的插件会覆盖之前添加的同名插件。

插件模块

插件模块是插件模块实例的构造函数。插件模块有两种类型:staticinstance。单个插件必须有一个或多个模块。插件模块可以返回一个实例,但不是必须的。

静态插件模块

static 插件模块在插件通过 OverlayScrollbars.plugin 函数添加时被调用。

带有 static 模块的插件示例:

js
const staticPlugin = {
  // 插件名称为 `examplePlugin`。
  examplePlugin: {
    // `static` 函数描述一个静态模块并返回模块实例,如果不需要实例则返回 void / undefined。
    // `osStatic` 参数是全局的 `OverlayScrollbars` 对象。
    static: (osStatic) => {
      let count = 0;
      const staticPluginModuleInstance = {
        getCount: () => count,
        increment: () => {
          count++;
        },
      };
      return staticPluginModuleInstance;
    },
  },
};

当插件通过 OverlayScrollbars.plugin 函数添加时,静态模块实例被返回:

js
const staticModuleInstance = OverlayScrollbars.plugin(staticPlugin); // 插件的静态模块被调用
staticModuleInstance.count; // 0
staticModuleInstance.increment();
staticModuleInstance.count; // 1

实例插件模块

instance 插件模块在创建新的 OverlayScrollbars 实例时被调用,但在 initialized 事件被分派之前。

带有 instance 模块的插件示例:

js
const instancePlugin = {
  // 插件名称为 `examplePlugin`。
  examplePlugin: {
    // 实例函数描述一个实例模块并返回模块实例,如果不需要实例则返回 void / undefined。
    // `osInstance` 参数是插件绑定的 OverlayScrollbar 实例。
    // `event` 参数是一个函数,用于向实例添加无法从插件外部移除的事件。
    // `osStatic` 参数是全局的 OverlayScrollbar 对象。
    instance: (osInstance, event, osStatic) => {
      let count = 0;
js
const instancePluginModuleInstance = {
  getCount: () => count,
  increment: () => { count++ },
}

// 当实例被初始化时触发的事件。
event('initialized', () => {
  console.log("instance initialized");
});

// 当视口滚动时触发的事件。
const removeScrollEvent = event('scroll', () => {
  console.log("viewport scrolled");
  removeScrollEvent(); // 在第一次滚动后移除事件。
});

return instancePluginModuleInstance;
}
}
}

当插件通过 OverlayScrollbars.plugin 函数添加时,从那时起所有的 OverlayScrollbar 实例将自动添加该插件。之前创建的实例将不会有该插件。实例模块实例通过 osInstance.plugin 函数返回:

js
OverlayScrollbars.plugin(instancePlugin); // 插件已添加

const osInstance = OverlayScrollbars(document.body, {}); // 插件的实例模块被调用
const instancePluginInstance = osInstance.plugin(instancePlugin);

instancePluginInstance.count; // 0
instancePluginInstance.increment();
instancePluginInstance.count; // 1

TypeScript

ts
// 描述一个 OverlayScrollbar 插件。
type Plugin<
  // 插件的名称。
  Name extends string = string,
  // 静态模块的模块实例类型。
  S extends PluginModuleInstance | void = PluginModuleInstance | void,
  // 实例模块的模块实例类型。
  I extends PluginModuleInstance | void = PluginModuleInstance | void
> = {
  [pluginName in Name]: PluginModule<S, I>;
};

// 描述一个只有静态模块的 OverlayScrollbar 插件。
type StaticPlugin<
  Name extends string = string,
  T extends PluginModuleInstance = PluginModuleInstance
> = Plugin<Name, T, void>;

// 描述一个只有实例模块的 OverlayScrollbar 插件。
type InstancePlugin<
  Name extends string = string,
  T extends PluginModuleInstance = PluginModuleInstance
> = Plugin<Name, void, T>;
typescript
// 推断传递的插件的静态模块实例的类型。
type InferStaticPluginModuleInstance<T extends StaticPlugin>;

// 推断传递的插件的实例模块实例的类型。
type InferInstancePluginModuleInstance<T extends InstancePlugin>;

常见问题

如何获取/设置应用了 OverlayScrollbars 的元素的滚动位置

如果你将 OverlayScrollbars 应用于 body 元素,你可以使用 window.scrollXwindow.scrollYwindow.scrollwindow.scrollTowindow.scrollBy 或任何其他原生 API。

如果插件应用于其他元素,你需要首先使用 instance.elements() 函数获取 viewport 元素。对于这个元素,你可以使用 element.scrollTopelement.scrollLeftelement.scrollelement.scrollToelement.scrollBy 或任何其他原生 API。

js
const { viewport } = osInstance.elements();
const { scrollLeft, scrollTop } = viewport; // 获取滚动偏移
viewport.scrollTo({ top: 0 }); // 设置滚动偏移
是否可以限制/调整滚动条手柄长度

你可以通过设置 min-width / min-heightmax-width / max-height 样式来调整滚动条的手柄长度:

css
/* 水平边界 */
.os-scrollbar-horizontal .os-scrollbar-handle {
  min-width: 50px;
  max-width: 200px;
}
/* 垂直边界 */
.os-scrollbar-vertical .os-scrollbar-handle {
  min-height: 40px;
  max-height: 40px;
}

你可以为两个属性分配相同的值,以强制滚动条始终保持相同的大小。
设置 widthheight 属性无效,因为这些属性由插件自动设置。

v1 的功能比较

  • 缺少 scroll 功能。计划作为 plugin 提供。(进行中)
  • 尚不支持对 textarea 元素的初始化。计划作为 plugin 提供。(进行中)

未来计划

  • 提供基于插件的支持以弥补缺失的功能。(可树摇)
  • 在错误修复和增强方面进行频繁更新。(始终使用最新的浏览器功能)
  • 改进测试。(单元测试和浏览器测试)

使用者

许可证

MIT