CSS 滚动捕捉允许用户完成滚动之后将视口锁定到某个元素的位置。非常适合用来建立下面这样的应用:
实现滚动捕捉主要依靠两个属性:容器元素的 scroll-snap-type
属性,以及子元素的 scroll-snap-align
属性。最基本的使用方式如下:
专门建立的学习Q-q-u-n: 767273102 ,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习技巧
(从零基础开始到WEB前端项目实战教程,学习工具,全栈开发学习路线以及规划)
...
.container {
scroll-snap-type: y mandatory;
}
.child {
scroll-snap-align: start;
}
第一版中定义的属性与此不同,是通过 repeat
关键字实现的。
.container {
/* OLD */
scroll-snap-points-y: repeat(300px);
}
这种定义捕捉的方式很局限,只在间距均匀的捕捉点(evenly-spaced snap points)场景下有效,如果个别子元素尺寸与其他的不一样,就会有问题。
在撰写本文时,Firefox、Internet Explorer 和 Edge 都支持较早版本的规范,而 Chrome(69+)和 Safari 支持较新的基于元素(element-based)的方法。
你可以同时使用这两种方法(如果布局允许),以便支持这两类浏览器:
.container {
scroll-snap-type: mandatory;
scroll-snap-points-y: repeat(300px);
scroll-snap-type: y mandatory;
}
.child {
scroll-snap-align: start;
}
但我认为使用基于元素的语法才是更灵活的选择,你可以一个下载 polyfill 来支持尚不支持它的浏览器。本文中后续的例子我也都是使用最新的语法写的。
注意:
不幸的是,polyfill 并没有附带浏览器包,如果不使用构建工具的话,使用起来会有点麻烦。我发现一个最简单的方法是链接到 bundle.run 上的脚本,并在加载 DOM 后使用
cssScrollSnapPolyfill()
进行 polyfill 初始化。还需要指出的是,此 polyfill 仅支持基于元素的语法,而不支持repeat
方法。
滚动捕捉需要同时设置父元素(容器)属性和子元素属性。这与 Flex 布局和网格布局里概念类型。
下面分别介绍。
mandatory
值表示,在用户停止滚动时,浏览器必须 滚动到一个捕捉点;proximity
属性就没有严格——除非当前滚动的位置合适,否则 不会强制浏览器 滚动到捕捉点。以我的经验,当滚动停止在距离某个捕捉点几百像素内时,捕捉才会发生。
我在工作中发现,mandatory
能提供更一致的用户体验。但是,规范中也指出,在遇到内容元素比滚动容器还高的情况,使用这个值就有点危险。
如果这里的容器元素设置了 scroll-snap-type: mandatory
,它总是会吸附到元素的顶部或下面元素的顶部,使得这个超高元素的中间部分内容是难完整查看。
默认情况下,内容元素会吸附到容器的最边缘。我们可以通过设置容器的 scroll-padding
属性来做修改。它的语法与 padding
属性一样。
如果布局中出现有可能妨碍内容元素展示的物件(比如,固定标题),使用它就比较有用。
现在再来看看,可在子元素上应用的属性。
通过这个属性,可以指定元素的哪一部分吸附到容器上。可能的取值有三个:start
、center
和 end
。
这些值的含义是相对于滚动方向。如果是垂直滚动,start
指的是元素的顶部边缘。如果你水平滚动,它指的是左边缘。center
和 end
属性值与此同理。属性还支持两个值的语法,分别指定水平和垂直方向上的捕捉对齐方向。
注:以
scroll-snap-align: start end;
为例,此处第一个值表示垂直滚动时的对齐点,第二个值则表示水平滚动。更多内容,可以参考 MDN 文档。
默认情况下,滚动捕捉只会在用户停止滚动时发生,这表示如果滚动过猛,中间可能会跳过几个捕捉点,然后才会停止。可以通过给子元素设置 scroll-snap-stop: always
来改变这一行为。这会将强制滚动容器在用户继续滚动之前停留在在就近的一个元素上。
在写这篇文章的时候,还没有浏览器原生支持 scroll-snap-stop
属性,尽管 Chrome 有一个 tracking bug 在。
让我们看一些使用滚动捕捉的例子。
实现垂直吸附滚动只需用到几行 CSS。首先,我们告诉容器沿其垂直轴捕捉:
.container {
scroll-snap-type: y mandatory;
}
专门建立的学习Q-q-u-n: 767273102 ,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习技巧
(从零基础开始到WEB前端项目实战教程,学习工具,全栈开发学习路线以及规划)
然后,定义吸附点(snap points)。这里,我们指定列表元素的顶部是吸附点:
.child {
scroll-snap-align: start;
}
为了实现水平滑块,我们告诉容器沿其 x 轴对齐。我们还使用 scroll-padding
确保子元素在容器中心处对齐。
.container {
scroll-snap-type: x mandatory;
scroll-padding: 50%;
}
然后,我们告诉容器要吸附到哪个点。为了将图库(gallery)居中,我们将每个元素的中心点定为吸附点。
.child {
scroll-snap-align: center;
}
我们可以直接在 HTML 元素上设置捕捉点:
html { /* body won't work ¯\_(ツ)_/¯ */
scroll-snap-type: y mandatory;
}
专门建立的学习Q-q-u-n: 767273102 ,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习技巧
(从零基础开始到WEB前端项目实战教程,学习工具,全栈开发学习路线以及规划)
然后,使每个部分的大小与视口一样,并将顶部边缘定义为捕捉点:
section {
height: 100vh;
width: 100vw;
scroll-snap-align: start;
}
效果:
**这与垂直版本具有相类似,不够捕捉点位于 X 轴上。
body {
scroll-snap-type: x mandatory;
}
section {
height: 100vh;
width: 100vw;
scroll-snap-align: start;
}
效果(demo):
滚动捕捉可以同时在两个方向上进行。
.container {
scroll-snap-type: both mandatory;
}
专门建立的学习Q-q-u-n: 767273102 ,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习技巧
(从零基础开始到WEB前端项目实战教程,学习工具,全栈开发学习路线以及规划)
然后,我们将每个图块的左上角定义为捕捉点:
.tile {
scroll-snap-align: start;
}
效果:
基于 CSS 的滚动捕捉的伟大之处在于,你无需直接控制滚动位置。取而代之的是,只需向浏览器提供一个位置列表,系统会自动以适合当前平台的首选项方式做捕捉处理。这表示我们缩写的滚动捕获效果感觉很匹配系统风格(使用了使用相同的动画效果)。
对我来说,这是 CSS 滚动捕捉优于提供类似功能的 JavaScript 库的主要优势。
根据我的经验,这在移动设备上效果还不错。也许是因为滚动捕捉已经是移动平台上本机 UI 的一部分(iOS 和Android 设备上主屏的 App 图表,本质上就是带有捕捉点的水平滑块)。Android 的 Chrome 上的交互特别好,因为它感觉像是自然的滚动效果,但视口总是碰巧刚好的地方停止滚动:
在这背后肯定有一些梦幻的数学公式使之成为现实。感谢 CSS 滚动捕捉,为我们免费提供了这么好用的效果。淡然,这种效果也不要滥用在不合适的其他地方,我们可以把当做一种增强效果是哦也能,比如幻灯片滚动效果这些,似乎是不错的选择。当然,可能也有其他方面的潜力,我没想到的。
CSS 捕捉点使你能够与浏览器的本机滚动交互挂钩,令界面达到无缝流畅的效果。随着可能的 JavaScript API 出现,这些功能将变得更加强大。