在我即将介绍的这个新的 CSS 之前,将元素锁定在视窗中 *在滚动时* 需要使用一些 JavaScript 代码。 您可能知道,JavaScript 在与滚动行为搭配使用时,有其令人难以置信的复杂性。
新的 CSS Scroll Snap Points 规范 有望提供帮助,允许使用非常少的 CSS 代码来实现此类行为。
正如非常新的 Web 技术一样,该规范已随着时间的推移而改变。 存在“旧”和“新”属性和值。 尽管如此,它很有希望,因为 支持 迅速增加。 我将教您如何在这一过渡阶段获得最广泛的支持。
Polyfilled 演示
下面的演示具有水平滚动。 它具有响应性:每个“面板”的宽度和高度都与视窗相同(感谢 vh
和 vw
单位)。
它使用了一个 polyfill,但是为了使用它(而且支持仍然不够高,因此我建议您这样做),您必须支持“旧”值,这就是为什么我还会介绍它们的原因。
查看 Pen 简单的响应式滚动捕捉点演示,作者是 CSS-Tricks (@css-tricks),在 CodePen 上。
- 如果您在 Firefox 中查看:它具有目前最佳的支持,因此您基本可以清楚地看到原生行为的外观和感觉。
- 如果您在 Chrome 或 Opera 中查看:没有任何支持,因此您在这些浏览器中注意到的任何行为都可以完全归因于 polyfill。
- 如果您在 Edge 或 IE 中查看:它可能根本无法运行。 这些浏览器 具有部分支持,但显然还不够让它运行。
- 如果您在移动设备上查看:iOS 9 支持它(在 iPhone 6 上测试),但我发现缓动行为非常奇怪。 没有 Chrome/Android 支持,但 polyfill 会启动并处理它(在 Android Nexus 6 上测试)。
请注意,我在 Pen 中使用 Autoprefixer 来自动为我提供所有必要的供应商前缀属性。
以下是用于制作魔法的代码
.scroller {
scroll-snap-type: x mandatory;
/* older spec implementation */
scroll-snap-destination: 0% 100%;
scroll-snap-points-x: repeat(100%);
}
.page {
scroll-snap-align: start;
}
非常简洁! 让我们逐个分解这些属性。
当前 CSS Scroll Snap 属性
scroll-snap-type
scroll-snap-type: none | mandatory | proximity;
mandatory
值可能就是您所想的那样:元素 *必须* 在捕捉点上静止,即使没有进行任何活动的滚动操作也是如此。 如果内容以某种方式修改或更新,页面会再次找到捕捉点。
proximity
值与 mandatory
相似,但不太严格。 如果浏览器大小发生变化或添加了内容,它可能会或可能不会再次找到捕捉点,具体取决于它距离捕捉点有多近。
从我使用它进行的尝试来看,mandatory
目前在浏览器中得到更广泛的支持,并具有更一致的行为。
scroll-snap-align
scroll-snap-align: [none | start | end | center] [none | start | end | center];
此属性指的是元素的滚动捕捉边距如何与其父滚动容器对齐。 它使用两个值,x
和 y
,如果您只使用一个值,它将被解读为简写并重复用于这两个值(类似于填充,其中 padding: 10px;
等于 padding: 10px 10px 10px 10px;
)。 此属性不可动画化。

scroll-snap-paddingscroll-padding
注意,scroll-snap-padding
已 重命名 为 scroll-padding
。
scroll-snap-padding: <length> | <percentage>;
scroll-padding: <length> | <percentage>;
此属性与视觉视窗中的滚动容器相关。 它与普通填充非常相似,具有相同的值顺序。 例如,scroll-padding: 75px 0 0;
将是 75px
的顶部填充,而其他填充都是 0
。 此属性可动画化,因此如果您需要移动滚动捕捉对齐,这将是一个好方法。
旧的 CSS Scroll Snap 属性
如前所述,该规范在过去的一年中一直在迅速变化,并且已经存在一些被认为过时的属性,尽管从遗留支持的角度来看,它们仍然值得了解。
scroll-snap-points
scroll-snap-points-<x or y>: none | repeat(<length>);
scroll-snap-point
指的是滚动方向的轴。 在我们看到的第一个 Pen 中,此属性是在 x
轴上设置的。 在这里,我们使用 scroll-snap-points-y: repeat(100%);
在 y
轴上设置它(因为它是一个垂直滚动)。 百分比指的是您定义为滚动容器的任何内容的填充框。
查看 Pen 简单的滚动捕捉点,作者是 Sarah Drasner (@sdras),在 CodePen 上。
scroll-snap-destination
此属性和 scroll-snap-coordinate
在值方面非常相似。 scroll-snap-destination
指的是父元素,而 scroll-snap-coordinate
指的是 *元素* 本身。 如果捕捉点纯粹由元素而不是它所在的容器指定,您可能只需要指定 scroll-snap-destination
。
scroll-snap-destination: <position>;
此属性允许您指定滚动应该在视窗中的哪个位置捕捉。 例如,假设您想让内容偏移 100px,以便两个面板中的一个面板被戏弄到另一个面板的一侧。 下面的图表显示了滚动捕捉目标将如何让您轻松调整此参数。

当定义为百分比时,该点相对于滚动容器的宽度和高度。
scroll-snap-coordinate
Scroll-snap-coordinate: none | <position>;
此属性允许您指定滚动应该在元素中的哪个位置捕捉。 位置量指的是元素的边框框。 除非您正在做一些非常花哨的事情,否则您可能不需要它。 scroll-snap-coordinate
是唯一可以应用于页面上所有元素的值,其他滚动捕捉属性仅应用于滚动容器。

最后这两个属性,scroll-snap-destination
和 scroll-snap-coordinate
是 *可动画化* 属性,而 scroll-snap-type
和 scroll-snap-points
—
更多资源
浏览器支持
此浏览器支持数据来自 Caniuse,其中包含更多详细信息。数字表示浏览器在该版本及更高版本中支持该功能。
桌面
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
69 | 68 | 11* | 79 | 11 |
移动/平板电脑
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
127 | 127 | 127 | 11.0-11.2 |
结论
截至本文发布时,规范大约一个月前更新过,并且仍在发展中。支持尚未普及,但即使您需要考虑 polyfill 所需的旧值,使它工作所需的代码也小巧简洁。看到 CSS 中即将出现的新功能非常令人兴奋,如果您进行实验,一定要让规范作者知道您在做什么以及您发现了什么——这确实会影响他们正在进行的工作。我仍然对在生产环境中使用这样的东西持观望态度。这将取决于您在未来遇到代码变更时愿意进行多少迭代。不过,目前,polyfill 的性能相当不错,看到这类东西在 CSS 中落地令人兴奋。
嗨。
虽然它很酷,但我认为这个功能“不会到来”。
我认为它在甚至被加入之前就被移除(弃用)了。
请点击您提供的 MDN 链接,阅读顶部红色“已弃用”消息。
嗨,
我认为这仅指属性“scroll-snap-points-x”,而不是整个模块,对吧?
请点击我们提供的规范链接,然后查看
……这是最新的,我认为这表明它正在前进。
我将更新 MDN 链接,指向更相关的子功能,因为那个看起来像是“旧”属性之一。
我用通用链接更新了它,但有些东西被恢复了,现在已修复!这是我们想要的链接:https://mdn.org.cn/en-US/docs/Web/CSS/CSS_Scroll_Snap_Points。
这个完整的规范并没有被弃用,而是迁移到了不同的实现。在文章中,我对此进行了说明,还解释了为什么在过渡阶段,仍然值得关注一些旧属性——主要是因为 polyfill 仍然使用它们。
规范可能在未来还会再次迁移,但幸运的是,即使支持旧值,也只需要很少的代码就能实现很多功能。
什么时候开发人员才能学会把滚动留给用户?我立即关闭任何以任何理由使用 scrolljacking 的网站。如果您想让它“捕捉”到下一个区域,请提供一个箭头供用户点击。**不要更改默认行为**。
这个功能绝对糟糕的例子
我使用垂直显示器。内容通常(如果不是总是)会停留在过高或过低的位置。使用此功能,我无法将内容定位到舒适阅读的位置,因为开发人员为我决定了我可以滚动内容的距离。我要么禁用 CSS 来阅读他们的内容(就像我会费心那样?),要么忍受不舒服的阅读(提示:我不会)。
对于任何想将此行为添加到其网站的人:请考虑您的用户!将其作为用户需要**选择加入**的替代方案(例如,点击左右箭头),**不要破坏默认设置**。
嘿,Nadya,我完全同意你的观点,但是我认为这实际上归结为实现解决方案的开发人员没有为任何类似肖像模式的东西(而不仅仅是传统的横向模式)提供支持。
通过正确的实现,它可以工作,但大多数情况下,你所经历的是正确的。然而,对于 CSS 的任何功能来说,都是如此。
我在这两种观点中都看到了道理。
我担心这种争论会变得有点教条主义。
毕竟,如果没有浏览器提供的默认滚动行为,那又是什么?而这正是浏览器提供(或将要提供)的滚动行为。
更像是“如果你做得好的话,你会喜欢它;如果你做得不好的话,你会讨厌它”。
“弹性滚动”并不总是存在。并不是每个人都喜欢它,但大多数人确实喜欢它,大多数人只是把它放在一边。他们没有拿出“永远不要改变滚动!!”的论点。
这些演示对于我来说是游走在边缘的,取决于体验。第一个演示,在桌面 Chrome 中,感觉有点不太好。感觉有点被劫持了,并且对它应该滚动的方向有自己的想法。但同样的演示在 Firefox 中感觉好多了。我可以想象,在未来经过几轮迭代后,它将在支持良好的移动浏览器中变得像弹性滚动一样流畅和美观。
@Damian
这是一个问题的一部分,但它是我已经习惯了的问题。许多,许多网站在我的“略大于平板电脑”的屏幕尺寸下会崩溃。我知道这一点,预料到了这一点,并且通常会绕过它(我在访问/定期阅读的任何网站上使用 Stylish 更改 CSS)。
我仍然在横向视图中使用此功能,但使用的是 JS 而不是 CSS,而不是我想要阅读的位置。一大问题是,没有测试它对不同窗口尺寸的工作情况,但它永远无法解释人们喜欢在哪里阅读。
我喜欢在文本从我的显示器下方 1/5 处开始的地方阅读。其他人喜欢在正中间。其他人喜欢在读完最后一行时往下滚动。当你为这些用户指定滚动时,你就不再为他们中的任何一个人提供服务,并且会积极地破坏他们的体验。
我不认为故意夺取用户控制权与未能为每种可能的屏幕尺寸编写代码是等同的。我想不出任何其他能破坏 UX 的 CSS 功能,除了自定义光标。谢天谢地,人们已经大多停止使用它们了。
@Chris
我的浏览器允许我自定义我想要的大多数东西。我禁用平滑滚动。我甚至可以选择更改我的滚动速度,使我的浏览器以我想要的速度精确滚动。我可以选择让它加速或保持恒定,因为我一直滚动。
如果我想以不同的方式更改它们——我会自己更改它们。而不是在 10 个不同的网站上拥有 10 种不同的滚动方式,因为开发人员认为他们比我更了解。
我不介意平滑滚动比其他更受欢迎。只要它是我可以禁用的东西,我就不会在乎它是否成为其他人的默认设置。重要的是**我控制着它**。
顺便说一句,我也退出强制平滑滚动的网站。没有所谓的“做得很好”。这是一种令人讨厌的体验,我不想忍受。我知道我是一个为用户控制而战的激进少数群体。
我认为 scrolljacking 最大的问题是,无论屏幕上为用户设计的体验是什么,始终有一件浏览器或操作系统无法修复的事情:触觉反馈。任何使用带有滚动轮的鼠标(或触控板/触摸屏或任何其他物理滚动机制)的人都会按照特定方向滚动、滑动、按压、推拉,并希望在他们面前的屏幕上看到他们行动的实时反馈。scrolljacking 通过更改我们的物理交互在屏幕上的转换方式来打破这种预期的反馈行为。
任何让用户感觉他们的硬件发生故障的功能,我都不想看到。/吐槽结束
@Chuck 我完全同意你的观点。而且这与实现的质量无关。
@Plopz 非常正确。拥有这个功能会显示常见的滚动条,但行为方式不同,这就是问题所在。如果为此创建一个新的浏览器组件,那么我可能会使用它。
至少在 Firefox 的实现中,即使稍微保持滚动位置也会覆盖捕捉。快速滚动手势会在捕捉中移动,但如果你保持位置,它就会停留在那里,尊重你想要的滚动位置。
我实际上不知道这是否是标准的一部分,但如果不是,那么它应该成为标准的一部分。
我认为滚动条不是控制这种体验的正确 UI 元素。问题是滚动条没有改变来表示将要发生的事情。也许如果滚动条重新设计为显示断点。但这种行为似乎更适合于方向按钮(左右箭头)或索引按钮(1、2、3、4、5……)。
目前,我希望避免网站上出现任何滚动行为。直到我看到一些在所有浏览器中都能正常工作且具有实际用例的复杂解决方案。
谢谢!
HP
我必须承认,我对这成为一个趋势并不太兴奋。也许在未来某一天可以接受,但在此期间,它可能会导致更多令人讨厌的网站。
嗨,Sarah,你想帮助贡献这个 polyfill 吗?
我已经添加了一个自己的 PR:https://github.com/ckrack/scrollsnap-polyfill/pull/7
如果我们可以联系 ckrack 并让他审查这些 PR,那就太好了。
嗨,Martin!是的,当然!我会在这个周末看一下。如果它得到更新,我们就不必再支持旧值了。
谢谢!
我宁愿看到这些实现中滚动被禁用,并添加一个部分导航。我一直反对任何类型的滚动劫持,至少要提供一个导航,这样我就不必等待动画完成,也不必因为滚动太多而跳回到上一节。我大多数时候都希望能够快速浏览网站。这个功能将始终取决于所需的 UX,“我想要控制用户还是让他们控制产品?我应该给他们多少控制权?” 尽管如此,看到一些标准正在出现还是很棒的。
如果(无论出于何种原因),用户想要滚动到快照点之间的某个点,怎么办?别劫持我的滚动,兄弟!
你不用使用 'mandatory' - 你也可以使用 'proximity'。我在演示中使用了 mandatory,因为它支持性更好,也更能展示其功能。
不过,我确实理解你说的,以及人们为什么对此持批评态度。我自己也持批评态度。但我认为学习这些工具仍然很重要,因为你可能有一天会遇到客户的用例,了解你所批评的东西也有用,因为正如这条评论中所展示的那样,这里还有另一种方法。:)
我访问每个 pen 时都遇到 404 错误。你能检查一下吗?
我没有遇到这种情况 - 请你检查一下你的连接或尝试使用其他浏览器访问?
哇,如果禁用或限制第三方 Cookie,页面就会显示 404 错误。这是个什么奇怪的系统?我已经好几年没从事这个行业了,但我一直以为 404 错误意味着“文件未找到”,而不是“伙计,我需要 Cookie”。:)
这里有很多负面评论,但让我添加一个关于此功能的正面用例。
在移动设备上,许多应用程序使用选项卡导航模型,在面板之间进行水平滚动。以 Facebook Messenger 为例。使用滚动快照,这种行为可以实现,而无需使用 JS。
天啊,我希望它永远不要进入现实。