滚动贴靠事件

Adam Argyle
Adam Argyle

从 Chrome 129 开始,您可以使用 JavaScript 中的 scrollSnapChangescrollSnapChanging 事件。通过实现内置的贴靠事件,之前不可见的贴靠状态将在适当的时间变得可操作且始终正确。如果没有这些事件,您就无法享受这种便利。

浏览器支持

  • Chrome:129.
  • Edge:129。
  • Firefox:不受支持。
  • Safari:不受支持。

来源

浏览器支持

  • Chrome:129.
  • Edge:129。
  • Firefox:不受支持。
  • Safari:不受支持。

来源

scrollSnapChange 之前,您可以使用交叉观察器来查找哪个元素越过了滚动端口,但确定哪些元素被贴靠仅限于某些情况。例如,您可以检测固定项是否填满滚动端口或填满滚动端口的大部分区域。为此,您需要观察滚动区域的交叉元素,然后根据占用滚动区域大部分空间的项,假定它是固定目标,然后等待 scrollend 并对固定的项(固定目标)执行操作。

不过,在 scrollSnapChanging 之前,我们无法知道何时会发生贴靠目标更改,也无法知道更改为何值(例如在滚动快速滑动时)。

显示一个水平滚动条,其中包含编号的方框作为贴靠目标。左侧是 scrollSnapChange 事件的实时日志,其中以蓝色突出显示了 snapTargetInline。右侧是 scrollSnapChanging 事件的实时日志,其中以灰色突出显示了 snapTargetInline。

试用
https://codepen.io/web-dot-dev/pen/jOjaaEP

好消息是,这些新事件可让您快速轻松地获取此类信息。这解锁了滚动贴靠互动,使其超越当前的功能,并支持协调滚动贴靠关系和全新的界面反馈场景。

scrollSnapChange

只有在滚动手势导致新的固定目标被停靠且按以下顺序发生时,此事件才会触发

  1. 滚动停止后。
  2. scrollend 之前。

此事件会在滚动完成时(即 scrollend 之前)触发,并且仅当停靠在新的固定目标上时才会触发。这样,当滚动手势完成时,事件会感觉是延迟触发或恰到好处触发。

scroller.addEventListener('scrollsnapchange', event => {
  console.log(event.snapTargetBlock);
  console.log(event.snapTargetInline);
})

scroller.onscrollsnapchange = event => {
  console.log(event.snapTargetBlock);
  console.log(event.snapTargetInline);
}

该事件会将事件对象上的固定项公开为 snapTargetBlocksnapTargetInline。如果滚动条仅限水平滚动,则 snapTargetBlock 属性将为 null。该属性的值将是元素节点。

scrollSnapChange 的唯一详细信息

在用户松开手势之前不会触发

如果手指仍在屏幕上或手指仍在触控板上,则表示用户的手势尚未完成滚动,这意味着滚动尚未结束,这意味着固定目标尚未更改,它正在等待用户手势完成。

如果固定目标未更改,则不会触发

此事件用于捕获卡顿变化,如果卡顿目标未发生变化,则不会触发此事件,即使用户与滚动条互动也是如此。不过,用户实际上确实滚动了,因此在滚动完成后,系统仍会触发 scrollend 事件。

scrollSnapChanging

一旦浏览器确定滚动手势已或将会产生新的固定目标,此事件就会触发。它会立即触发,并在滚动期间触发。

scroller.addEventListener('scrollsnapchanging', event => {
  console.log(event.snapTargetBlock);
  console.log(event.snapTargetInline);
})

scroller.onscrollsnapchanging = event => {
  console.log(event.snapTargetBlock);
  console.log(event.snapTargetInline);
}

该事件会将事件对象上的固定项公开为 snapTargetBlocksnapTargetInline。如果滚动条仅限垂直滚动,则 snapTargetInline 属性将为 null。该属性的值将是元素节点。

scrollSnapChanging 的唯一详细信息

在滚动手势期间尽早频繁触发

与等待用户完成滚动手势的 scrollSnapChange 不同,此事件会在用户用手指或触控板滚动时立即触发。假设用户在不抬起手指的情况下慢速滚动,只要用户在多个可能的固定目标上平移,scrollSnapChanging 就会在手势期间多次触发。每次用户滚动时,如果浏览器确定在松开手指后会停留在新的固定目标上,系统就会触发该事件,以告知您是哪个元素。

不会在到达新固定目标的过程中触发所有固定目标

此外,请考虑以下情况:用户执行一次滚动抛出手势,该手势同时跨越多个固定目标;此事件将针对最终停止的目标触发一次。因此,它是积极的,但不会浪费资源,会尽快为您提供快照目标。

使用场景和示例

这些事件支持许多新用例,同时也让当前模式更易于实现。一个典型示例是启用快拍触发的动画。在 snap 项是 snap 目标时,根据上下文显示 snap 项、snap 项的子项或关联信息。

以下模式展示了一些用例,可帮助您立即提高工作效率。

突出显示赞誉

此示例展示了如何宣传或视觉上突出显示抓拍的赞誉。

scroller.onscrollsnapchange = event => {
  scroller.querySelector(':scope .snapped')?.classList.remove('snapped')
  event.snapTargetInline.classList.add('snapped')
}
https://codepen.io/web-dot-dev/pen/dyBZZPe

显示已固定项的字幕

此示例显示了已固定项的标题。此演示包含这两种事件,以便您了解 scrollSnapChangescrollSnapChanging 之间的时间和用户体验差异。

Snap 更改
https://codepen.io/web-dot-dev/pen/wvLPPBL

快照更改
https://codepen.io/web-dot-dev/pen/QWXOObw

为已固定的演示文稿幻灯片的子项添加一次动画

此示例会知道新幻灯片何时到达并停留在屏幕上,这时非常适合对内容进行一次动画处理。

document.addEventListener('scrollsnapchange', event => {
  event.snapTargetBlock.classList.add('seen')
})
https://codepen.io/web-dot-dev/pen/rNEYYVj

在滚动条中同时在 x 轴和 y 轴上贴靠

滚动贴靠适用于允许水平和垂直滚动的滚动条。此演示会在您滚动网格时同时显示 scrollSnapChangingscrollSnapChange 目标。此演示说明了浏览器所附加的元素可能并不总是您认为的元素。

显示水平和垂直滚动条中的方格网格。虚线边框表示 scrollSnapChanging 目标,实线边框表示 scrollSnapChange 目标。红色代表 snapTargetInline,蓝色代表 snapTargetBlock。

https://codepen.io/web-dot-dev/pen/qBzVVdp

两个已关联的滚动条

此演示包含两个滚动贴靠容器,其中一个是链接的概要列表,另一个是实际的分页内容。借助新的 scrollSnapChanging 事件,您可以轻松地双向关联这些项的固定状态,以便它们始终保持同步。

https://codepen.io/web-dot-dev/pen/YzoEEXj

OKLCH 颜色选择器

此演示包含 3 个滚动条,每个滚动条都代表 OKLCH 中的不同颜色通道。固定项会与其相关的单选组同步,并且可以从封装输入项的表单中检索数据。对于鼠标或触控用户,您可以滚动到所需的值。对于键盘用户,您可以使用 Tab 键和箭头键。对屏幕阅读器而言,这只是一个表单。

scrollSnapChanging 用于提前将已固定的项与状态同步,而 scrollSnapChange 用于为应用了用户输入的受影响的颜色通道标题添加动画效果。

https://codepen.io/web-dot-dev/pen/OJeOOVG

快速捕获动画效果的动态枢纽

此演示通过使用 scrollsnapchange 实现的点按触发的转场效果,逐步改进滚动点按体验。

使用以下 JavaScript 检查事件支持情况:

if ('onscrollsnapchange' in window) {
  // ok to use snap change
}
https://codepen.io/web-dot-dev/pen/MWMOOae

可滚动的标尺输入

此演示采用可滚动标尺作为为数字输入选择长度的替代方式。直接在数字输入框中输入值,或滚动到相应大小。changing 事件用于在用户执行手势期间清除选择,而 change 事件用于更新状态并确认用户的选择。

https://codepen.io/web-dot-dev/pen/LYKOOpd

封面照片

此演示基于 Bramus Van Damme 对著名 macOS 封面流的出色滚动驱动型动画再现视频教程)。独特的是,scrollSnapChanging 用于隐藏专辑标题,scrollSnapChange 用于显示标题。这些事件有助于协调以极速方式隐藏旧标题并以延迟方式显示新标题。

https://codepen.io/web-dot-dev/pen/Bagmmog

更多有助于激发创意的想法

现在,我们可以轻松了解哪个元素即将贴靠,哪个元素正在贴靠,这为我们提供了许多新的可能性!以下是一些有助于激发创意和发现更多用例的想法:

  • 触发延迟加载,也称为“snapchange 触发的渲染”或“数据提取”。
  • 与较大图片相关联的幻灯影片缩略图。
  • 为已固定的视频缩略图切换视频预告片的播放/暂停状态。
  • Google Analytics 跟踪
  • 滚动式讲述
  • “幸运轮”界面/用户体验
  • 贴靠目标会获得锚定的提示。
  • 点按即可自动对齐
  • 快速拍照即可显示
  • 快拍时发出提示音
  • 滑动界面
  • 可滑动的标签页或轮播界面

后续研究

Chrome 团队非常期待听到您使用这些新 API 构建的内容,并希望这些 API 有助于简化滚动体验。

资源: