CSS Snap Points 实现滚动吸附

许多作为 Web 开发者的你,正试图实现复杂的滚动效果,例如分页滚动。WebKit 现在通过 CSS Snap Points 支持分页滚动。尽管一些 JavaScript 滚动库已经允许你在网站和 Web 视图中实现分页滚动,但这些方法存在重要的缺点——首先,它们在滚动动画的每一帧都运行 JavaScript,这是 WebKit 的快速滚动基础架构无法优化的。其次,当前的事件模型标准不暴露触控板滚动阶段,这使得你很难使用 JavaScript 实现最佳的分页滚动。幸运的是,有了滚动吸附,你将不需要有关滚动阶段的信息来实现出色的分页滚动。

新的 CSS 属性

滚动吸附允许你使用 CSS 在可滚动容器的内容中定义特殊的点。当用户在此容器中滚动时,滚动偏移量将停在这些特殊偏移量之一上。为了阐明滚动吸附,请看这个水平滚动的画廊

注意滚动是如何让我们停留在尴尬的位置,只能看到一张图片的一小部分和下一张图片的部分。让我们看看如何使用新的 scroll-snap-* 属性来实现分页滚动。请注意,本文中显示的所有示例都可以在这个滚动吸附画廊中找到。

滚动吸附类型

默认情况下,父级滚动容器上的 scroll-snap-typenone,这表示容器不选择任何滚动吸附行为。要启用,我们将值设置为 mandatory,这保证了在没有活动滚动操作时,容器的可视视口将停留在吸附点上。另请注意,scroll-snap-type 的另一个值为 proximity,这表示只有当滚动将我们带到吸附点附近时,滚动才会停留在吸附点上。目前,WebKit 只支持强制吸附。

滚动吸附点 -X 和 -Y

scroll-snap-points-xscroll-snap-points-y 属性分别决定了如何在滚动吸附容器的水平和垂直轴上放置吸附点。这里的值可以是 none(默认值)或 repeat(length),其中 CSS length 单位表示任何表示长度的表达式。这些包括原始像素值、视口单位、百分比(相对于容器的内边距框)甚至 calc() 表达式。请注意,负的 repeat() 值被视为解析错误,并且任何小于 1px 的值都将被限制在 1pxrepeat() 值表示吸附点应分别沿着 x 或 y 轴以固定间隔放置。使用上述两个属性,这是一个强制滚动吸附的示例,使用 repeat(100%) 在容器宽度的每隔 100% 处设置水平吸附点。如果你使用的浏览器支持滚动吸附,你也可以查看 滚动吸附演示 1

每个吸附点都位于每张图片的左上角。滚动吸附使得每个吸附点都停留在容器的左上角,以蓝色十字标记。

滚动吸附坐标

如果我们的图片大小不同,我们将无法使用 repeat(),因为间隔会因图片而异。取而代之的是,我们可以在子元素上使用 scroll-snap-coordinate 来生成一个或多个相对于每个子元素的吸附点。此属性接受“none”或空格分隔的坐标列表。每个坐标的形式为 length length,分别表示坐标的 x 和 y 位置。就像之前一样,每个 length 都被泛化以匹配任何通用长度值,并且基于百分比的长度值使用子元素的边框盒尺寸。以下示例在每个子元素的左上角放置一个吸附坐标,使我们能够吸附到间隔不均匀的元素。请参见 滚动吸附演示 2

滚动吸附目标

改进画廊的另一种方法是将每张图片相对于容器居中。到目前为止,我们一直将每个吸附点对齐到父容器的左上角。然而,通过更改 scroll-snap-destination,我们可以控制吸附点动画到的位置。目标值是一个由两个空格分隔的 length 组成的单个位置。基于百分比的值是相对于滚动吸附容器的内边距盒计算的。我们将此属性与每个子元素上的 scroll-snap-coordinate 结合使用,将每个子元素动画到容器的中心。请参见 滚动吸附演示 3

请注意,蓝色十字的位置现在位于容器的中心,因为我们将目标设置为 50% 50%。吸附点也现在位于每个子元素的中心,因此每个子元素的中心现在会停在容器的中心。

附加细节

我们的滚动吸附实现也支持 2D 吸附,当两个轴的滚动吸附点都处于活动状态或当元素在容器中以网格状方式定位时。对角线滚动会沿着弯曲路径动画滚动偏移量到其目标位置。请参见 滚动吸附演示 4

我们还支持对已应用 CSS 转换的容器进行滚动吸附。请参见 滚动吸附演示 5

标准兼容性和未来工作

我们目前只支持吸附点规范中最完整的部分:对齐在网格上的子元素的 2D 滚动吸附。这意味着如果您的 2D 滚动容器包含大小不均匀的滚动吸附元素(例如在砌体网格布局中),您可能会发现比预期更多的吸附点。CSS Scroll Snap Points 规范仍在进行中。我们正在考虑 CSS Scroll Snapping Change Proposal。一旦达成共识,我们将实施替代的滚动模型,或者实施滚动吸附的 proximity 类型,其进度可在 bug 135994 中跟踪。由于规范仍在变化中,我们已根据 W3C 对尚未完成标准化流程的功能的要求,为我们的实现加上了 -webkit 前缀。一旦规范接近最终状态,我们打算移除滚动吸附属性的前缀。该规范也没有明确说明如何处理不可达的吸附点。我们当前的实现将每个吸附点的所有 x 和 y 偏移量限制在滚动吸附容器的最小和最大滚动偏移量范围内。此外,为了防止内容不可达,我们也在容器的最小和最大滚动偏移量处发出吸附点。您可以在 nightly 版本以及 OS X El Capitan 和 iOS 9 上的 Safari 中使用滚动吸附。我们希望您喜欢阅读关于滚动吸附的内容,并且我们很高兴看到您用它创造出什么!