CSS Scroll Snap允许网站在用户执行滚动操作时,将网页或任何其他滚动容器固定在一个特定的滚动位置。这个功能在所有现代浏览器中被支持了两年多,但许多可以从中受益的网站仍然没有使用它。
滚动抢答可能与水平旋转木马(见Chris的纯CSS方法)和划分为全屏幻灯片的特定网页最有关系。但为什么要止步于此呢?我相信,抢购可以改善任何以网格或feed方式排列项目的网页的滚动体验。
例如,大多数购物网站在网格中显示产品。理想情况下,用户希望以最小的努力在网格行之间跳跃。用户可以按空格键来滚动页面,大约是一个屏幕(视口高度),但根据网格行的高度,滚动位置最终会与网格 "不同步",用户将不得不手动重新调整它。
如果我们在这个页面上添加滚动捕捉功能,用户就可以一直用空格键滚动到下一行(按Shift+空格键会滚动到前一行)。这是很不费力的。
我认为,滚动抢答将是这个网站的一个受欢迎的补充。而且,它的实现也不是那么复杂。我在这个例子中使用的CSS代码是相对简单的。
html {
scroll-snap-type: y proximity;
}
.product-item {
scroll-snap-align: start;
scroll-margin-top: 75px; /* height of web page’s sticky header */
}
如果你经常访问的网站还没有添加滚动捕捉功能,而你认为它可以改善你的滚动体验,那么你就不必等待。你可以自己添加滚动捕捉功能--使用用户样式。
在网站上添加用户样式
在上面的视频中,你可以看到我在 Safari 的高级偏好中选择了一个 user.css 文件。这个文件是一个用户样式表。它包含了我编写的CSS样式,存储在一个本地.css ,并添加到Safari中。这些 "用户样式 "随后被应用到我在Safari中打开的每一个网页上。
Chrome和Firefox不允许用户选择一个用户样式表。火狐浏览器在过去支持一个类似的功能,称为userContent.css ,但该功能在2019年已被废弃,并默认禁用。我为这两个浏览器(以及其他基于Chromium的浏览器)推荐Stylus浏览器扩展。
Stylus的一个显著优势是,它允许你为特定网站和URL编写用户样式。Safari的用户样式表适用于所有网站,但这一点可以绕过,例如,通过使用新的:has() 伪类来创建只与特定网站匹配的选择器。

Stylus扩展已经被Chrome和Firefox团队审查,并获得了一个表示高标准的徽章。
CSS层叠模块为用户添加的样式定义了一个用户起源。Safari的用户样式表属于这个原点,但Stylus扩展将用户样式注入到网站样式表所在的作者原点。具体来说,Stylus通过<html> 结尾处的一个<style> 元素,直接将用户样式插入到页面中,使其成为页面的最终样式表。从技术上讲,这意味着通过Stylus添加的样式被归类为作者样式,因为它们不在用户本源中,但我将继续称它们为用户样式,因为是用户添加的。
然而,值得注意的是,这种区别会影响级联。当选择器的特异性相同时,真正的用户样式要比页面自身的样式弱。这使得用户样式成为 用户默认的绝佳选择。在同样的条件下,通过Stylus添加的样式要强于页面的样式,所以Stylus不能轻易地用来定义用户默认值。
如果我们把!important ,真实的用户样式和通过Stylus添加的样式都会比页面的样式更强。因此,当你想在一个网站上强加你的用户样式时,不管你是使用Safari的 "样式表 "选项还是Stylus扩展,都没有关系。无论是哪种方式,你的!important 样式都会获胜。
在下一节中,我将使用一组!important 用户样式,在Twitter网站的时间轴页面上强制执行滚动捕捉。我的目标是通过避免尴尬的滚动位置,即最上面的推文只在屏幕上的部分,来加快阅读我的Twitter时间线的过程。
推特时间线的滚动快照
经过一些实验,我确定了以下的CSS代码。这些样式在Firefox中运行良好,但我在Chrome和Safari中遇到一些问题。我将在文章后面更详细地描述这些问题,但现在,让我们专注于Firefox中的行为。
html {
scroll-snap-type: y mandatory !important;
}
/* tweets in the timeline are <article> elements */
article {
scroll-snap-align: start !important;
}
/* un-stick the sticky header and make it “snappable” as well */
[aria-label="Home timeline"] > :first-child {
position: static !important;
scroll-snap-align: start !important;
}
/* hide the “new Tweets available” floating toast notification */
[aria-label="New Tweets are available."] {
display: none !important;
}
有必要在每个声明中添加!important ,因为所有的用户样式必须胜过网页自己的样式,这样我们的自定义滚动捕捉实现才能正确工作。我希望不要重复写!important ,我可以把我的用户样式放在一个 "重要层 "中,但这样的CSS功能并不存在(目前)。
请看下面的视频,看看我的滚动快照用户样式的运行情况。请注意,每按一次空格键都会将下一组推文滚动到视野中,而且每组推文的第一条都会对准视窗的上边缘。这使我能够更迅速地阅读我的时间线。当我需要回到上一组推文时,我可以按Shift+Space。
我喜欢这种类型的滚动抢答的原因是,它允许我预测每当我按下空格时,页面会滚动多远。每个滚动距离等于完全在屏幕上的可见推文的综合高度。换句话说,位于屏幕底部的部分可见推文将移动到屏幕的顶部,这正是我想要的结果。

我事先知道,按下Space ,戴夫的推文就会滚动到屏幕的顶部。
要在你自己的Twitter时间轴上尝试我的滚动快照用户风格,请按照以下步骤进行:
- 用火狐浏览器附加组件或Chrome网络商店安装Stylus扩展。
- 导航到你的Twitter时间线,twitter.com/home。
- 点击浏览器工具栏上的Stylus图标,在弹出的窗口中点击 "这个URL"。
- Stylus将在一个新的浏览器标签中打开一个代码编辑器。把我的滚动快照用户样式复制粘贴到编辑器中,然后按左边侧边栏中的保存按钮。这些样式将立即应用到你的Twitter时间轴上(不需要重新加载页面)。
- 你可以在任何时候更新这些样式。点击手写笔图标和铅笔图标,再次打开编辑器。
无法重写抢答
我为Twitter的时间线实现的滚动捕捉有一个主要缺陷。如果一条推文比视窗高,就不可能滚动页面来显示该推文的底部(例如,如果你想喜欢或转发该推文),因为浏览器会强行扣住页面来显示该推文的顶部(或接下来的推文的顶部)。
这个问题的严重程度取决于用户的显示器。在一个大的桌面显示器上以小的页面缩放系数查看Twitter的时间线,你可能不会遇到任何比视口更高的推文。
我已经问过CSS工作组,是否有可能增加一种机制,允许用户覆盖浏览器的强制滚动捕捉。我也许应该提到,这个问题至少在理论上可以通过从mandatory 转到proximity 的抢购来解决。我在Chrome和Firefox中测试了proximity ,我发现它不连贯而且令人困惑。浏览器经常在我不期望的情况下进行抢购,反之亦然。也许是Twitter的代码干扰了proximity 算法,浏览器仍然有点问题,或者是我只是 "滚动错误",如果这有可能的话。我不知道。
但我采用mandatory 抢答的主要原因是,我想避免出现滚动后最上面的推文只在屏幕上一部分的情况。我在上面的视频中所展示的在各组推文之间快速滚动的类型,只有通过mandatory 抢答才能实现。
如果你像我一样喜欢mandatory ,我可以为 "高大的推文 "问题提出以下两个解决方法:
- 你可以在自己的页面上打开推文,之后再回到时间轴上。
- 如果你只想点击 "喜欢 "或 "转发 "按钮,你可以Shift点击推文来选择它,然后按L键来喜欢它,或者按T键和Enter键来转发它。
在Chrome和Safari中的问题
我的滚动抓取用户风格在Chrome、Safari和Firefox中产生了明显不同的滚动抓取行为。这些差异的部分原因是,抢购机制的具体实现是由浏览器决定的。
CSS滚动捕捉模块有意不指定也不授权任何精确的动画或物理学用于执行捕捉位置;这由用户代理决定。
当前版本的Safari浏览器有一个bug,它阻止了滚动抓取在Twitter时间线上的正常工作。我已经报告了这个错误。
在Chrome中,我遇到了以下问题:
- 滚动操作的动画效果不一致。有时动画很慢,有时是即时的,有时开始很慢,但后来又被缩短了。我发现这很令人恼火。
- 一般来说,滚动操作的动画速度太慢。我在Chrome和Firefox中进行了测试(按20次空格),在Chrome中覆盖我的Twitter时间线的相同距离,比Firefox多花了70%的时间(Chrome中18.5秒,Firefox中11秒)。
- 当我使用笔记本电脑的触控板滚动时,页面会出现很多闪烁。当我试图通过按住空格键来快速滚动时,页面的滚动速度非常慢,而且会出现震荡。我怀疑这两个问题都是由同一个算法引起的。在这些情况下,Chrome浏览器似乎以非常高的速度重新刷新。我已经报告了这个错误。
这些浏览器的错误和浏览器之间的差异对于考虑实施滚动捕捉的网站来说是一个问题。例如,网站开发者可能会因为不喜欢某个特定浏览器的滚动捕捉行为而按兵不动。浏览器可以通过提高互操作性来缓解这个问题。事实上,滚动捕捉是跨浏览器互操作2022努力的重点领域之一。
另一个可以改善这种情况的方法是引入新的CSS属性,使滚动捕捉更加可配置。这可以包括捕捉动画的持续时间,捕捉的接近阈值的长度,以及一个覆盖强制捕捉的机制。
捕捉或不捕捉?
我在Twitter的时间轴上使用我的滚动抓取用户风格已经有几个星期了,我不想再回去了。只用空格键就能快速翻阅我的信息,这简直是另一个层次。
然而,我认为这是一个高级功能,可能不适合所有人。我只在时间轴(/home path)上启用了这个功能,而在Twitter网站的其他地方没有启用,这是有原因的。抢答是页面滚动方式的一个重大变化,需要一些时间来适应。它可以在特定的使用情况下发挥很大的作用,但它也可能会妨碍用户,使用户感到沮丧。
因此,在仔细考虑并在不同的浏览器和不同的输入方式(鼠标、键盘、触控板、触摸屏等)中进行大量的测试之后,有feeds的网站应该考虑只将滚动抢答作为一个可选的功能。
在你走之前...
最后,我强烈建议安装并试用Stylus浏览器扩展。网络开发者(或任何懂得CSS的人)都有能力在浏览器中对任何网站进行样式设计。你可以对你喜欢的网站进行小的改进和修复。我主要是用它来隐藏我觉得讨厌的页面元素,如粘性标题、视频弹出窗口和投票数。
但更重要的是,Stylus允许你在任何网站上快速测试新的CSS功能,并在必要时报告浏览器的错误。通过这样做,你可以帮助使网络平台变得更好一些。