CSS 滚动捕捉 允许网站在用户执行滚动操作时将网页或任何其他滚动容器捕捉到特定的滚动位置。此功能在 所有现代浏览器中 已支持两年多,但许多可以从中受益的网站仍然没有使用它。
滚动捕捉可能与水平轮播最为相关(参见 Chris 的纯 CSS 方法)以及特定网页分成全屏幻灯片。但为什么止步于此?我相信捕捉可以改善任何以网格或提要形式布局项目的网页的滚动体验。
例如,大多数购物网站以网格形式显示产品。理想情况下,用户希望以最小的努力在网格行之间跳转。用户可以按下 空格键 将页面滚动大约一屏(视窗高度),但根据网格行的高度,滚动位置最终会与网格“不同步”,用户将不得不手动重新调整它。
如果我们将滚动捕捉添加到此页面,用户可以使用 空格键 始终滚动到下一行(按 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 不允许用户选择用户样式表。Firefox 过去支持类似的功能,称为 userContent.css
,但该功能已弃用,并在 2019 年 默认情况下禁用。对于这两个浏览器(和其他基于 Chromium 的浏览器),我推荐 Stylus 浏览器扩展。
Stylus 的一个重要优势是它允许您为特定网站和 URL 编写用户样式。Safari 的用户样式表适用于所有网站,但这可以通过以下方式解决,例如,使用新的 :has()
伪类来 创建仅匹配特定网站的选择器。

CSS 级联模块为用户添加的样式定义了 用户来源。Safari 的用户样式表属于此来源,但 Stylus 扩展将用户样式注入到网站样式表所在的作者来源。具体来说,Stylus 通过在 <html>
结束时使用 <style>
元素直接将用户样式插入页面,这使其成为 页面上的最终样式表。从技术上讲,这意味着通过 Stylus 添加的样式被归类为作者样式,因为它们不在用户来源中,但我将继续称它们为用户样式,因为用户添加了它们。
但是,值得记住这种区别,因为它会影响级联。当选择器特异性相等时,真正的用户样式比页面自身的样式更弱。这使得用户样式非常适合 用户默认值。在相同条件下,通过 Stylus 添加的样式比页面样式更强,因此 Stylus 不能像定义用户默认值那样轻松使用。
如果我们将 !important
添加到混合中,真正的用户样式和通过 Stylus 添加的样式都比页面样式更强。因此,当您想将用户样式强加于网站时,使用 Safari 的“样式表”选项还是 Stylus 扩展并不重要。您的 !important
样式无论哪种方式都会获胜。
在下一节中,我将使用一组 !important
用户样式来强制在 Twitter 网站的时间线页面上进行滚动捕捉。我的目标是通过避免尴尬的滚动位置(其中最上面的推文仅部分出现在屏幕上)来加快阅读我的 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 + 空格键。
我喜欢这种滚动捕捉类型的原因是,它使我可以预测每次按下 空格键 时页面将滚动多远。每次滚动距离等于完全出现在屏幕上的可见推文的组合高度。换句话说,屏幕底部部分可见的推文将移动到屏幕顶部,这正是我想要的。

空格键
会将 Dave 的推文滚动到屏幕顶部。要在您自己的 Twitter 时间线上尝试我的滚动捕捉用户样式,请按照以下步骤操作
- 使用 Firefox 附加组件或 Chrome 网上应用店安装 Stylus 扩展。
- 导航到您在 https://twitter.com/home 的 Twitter 时间线。
- 单击浏览器工具栏中的 Stylus 图标,然后在弹出窗口中单击“此 URL”。
- Stylus 将在新浏览器选项卡中打开一个代码编辑器。将我的滚动捕捉用户样式复制粘贴到编辑器中,然后按左侧边栏中的保存按钮。样式将立即应用于您的 Twitter 时间线(无需重新加载页面)。
- 您可以随时更新样式。单击 Stylus 图标,然后单击铅笔图标以重新打开编辑器。
无法覆盖捕捉
我为 Twitter 时间线实现的滚动捕捉有一个主要缺陷。如果推文比视窗更高,则无法滚动页面以显示该推文的下部(例如,如果您想喜欢或转发该推文),因为浏览器会强制将页面捕捉到显示推文顶部(或下一条推文顶部)。
此问题的严重程度取决于用户的显示器。在大型台式机显示器上以较小的页面缩放因子查看 Twitter 时间线时,您可能不会遇到任何比视窗更高的推文。
我已询问 CSS 工作组,是否可以添加一种机制,允许用户 覆盖浏览器的强制滚动捕捉。我应该提一下,这个问题至少在理论上可以通过从 mandatory
切换到 proximity
捕捉来解决。我在 Chrome 和 Firefox 中测试了 proximity
捕捉,发现它不一致且令人困惑。浏览器经常会在我不希望它捕捉时捕捉,反之亦然。也许 Twitter 的代码干扰了 proximity
算法,浏览器仍然存在一些错误,或者也许我只是“滚动错误”,如果可能的话。我不知道。
但我选择 mandatory
捕捉的主要原因是我想避免在滚动后最上面的推文仅部分出现在屏幕上的情况。我在上面的视频中展示的那种推文集之间的快速滚动仅在 mandatory
捕捉的情况下才有可能。
如果您像我一样更喜欢 mandatory
捕捉,我可以针对“高推文”问题建议以下两种解决方法
- 您可以打开推文的单独页面,然后返回时间线。
- 如果您只想单击喜欢或转发按钮,可以 Shift 单击推文以选择它,然后按 L 来喜欢它,或按 T 后跟 Enter 来转发它。
Chrome 和 Safari 中的问题
我的滚动捕捉用户样式在 Chrome、Safari 和 Firefox 中产生了明显不同的滚动捕捉行为。这些差异部分是由于滚动捕捉机制的具体实现 由浏览器决定
CSS 滚动捕捉模块有意不指定也不强制执行用于强制捕捉位置的任何精确动画或物理机制;这留给用户代理处理。
Safari 的当前版本存在一个错误,导致滚动捕捉在 Twitter 时间线上无法正常工作。我已经 报告了这个错误。
在 Chrome 中,我遇到了以下问题
- 滚动操作的动画不一致。有时动画很慢,有时是即时,有时开始很慢但随后被截断。我发现这很烦人。
- 滚动操作的动画总体来说太慢了。我在 Chrome 和 Firefox 中进行了一项测试(20 次 空格 按键),我用 Chrome 在 Twitter 时间线上覆盖相同距离的时间比 Firefox 多 70%(Chrome 18.5 秒 vs. Firefox 11 秒)。
- 当我使用笔记本电脑的触控板滚动时,页面会闪烁很多。当我尝试通过按住 空格 键快速滚动时,页面滚动速度非常慢并且会振荡。我怀疑这两个问题都是由相同的算法引起的。似乎 Chrome 在这些情况下以非常高的速率重新捕捉。我已经 报告了这个错误。
这些浏览器错误和浏览器之间的差异对于考虑实施滚动捕捉的网站来说可能是个问题。例如,Web 开发人员可能会犹豫不决,因为他们不喜欢滚动捕捉在一个特定浏览器中的行为方式。浏览器可以通过提高互操作性来缓解这个问题。实际上,滚动捕捉是跨浏览器 Interop 2022 工作 的重点领域之一。
另一种改善现状的方法是引入新的 CSS 属性,这些属性可以让滚动捕捉更具可配置性。这可能包括捕捉动画的持续时间、捕捉的临近阈值长度以及覆盖强制捕捉的机制。
捕捉还是不捕捉?
我已经在我的 Twitter 时间线上使用我的滚动捕捉用户样式几个星期了,我不想再回到以前。能够仅用 空格 键快速翻阅我的 feed,真是太棒了。
但是,我认为这是一个高级功能,可能不适合所有人。我之所以只在时间线上(/home
路径)启用它,而没有在 Twitter 网站上的其他地方启用它,是有原因的。捕捉是页面滚动方式的重大改变,需要一段时间才能适应。它对于特定用例来说非常有效,但也可能会妨碍用户并造成挫败感。
因此,具有 feed 的网站应该考虑仅将滚动捕捉作为一项可选功能提供,在经过仔细考虑并在不同浏览器和使用不同输入方式(鼠标、键盘、触控板、触摸屏等)进行大量测试后才能提供。
在你离开之前…
最后,我强烈建议你安装并试用 Stylus 浏览器扩展。Web 开发人员(或任何了解 CSS 的人)都有权在浏览器中为任何网站设置样式。你可以对你的最爱网站进行一些细微的改进和修复。我主要用它来隐藏我认为很烦人的页面元素,例如粘性页眉、视频弹出窗口和投票计数。
但更重要的是,Stylus 允许你快速在任何网站上测试新的 CSS 功能,并在必要时报告浏览器错误。通过这样做,你可以帮助使 Web 平台变得更好。
这是一个非常酷的 CSS 技巧,也是对用户样式功能的很好的介绍!我一定要自己试一试!
用户样式可以成为非常强大的工具,可以让网站再次变得易于访问、可用、整洁,并且应该成为更普遍的知识。类似于你在 Twitter 上使用滚动捕捉来获得更好的用户体验的实验,我创建了自己的用户样式表,完全删除了 Twitter 的右侧边栏。它让 Twitter 变得更加平静!
我知道这只是一个实验,但如果你真的想以一致的方式获得这种行为,可以使用 Twitter 快捷键(Shift + ? 显示列表)。它可能使用 JS 来完成它的工作,但效果很好。而且大多数现代网站都有这样的快捷键。
Twitter 提供的一个键盘命令最接近我的滚动捕捉实现,就是使用 J 键滚动到视图并聚焦下一条推文。
还不错,但对我来说太慢了。我希望能够将下一**组推文**滚动到视图中,而不仅仅是下一条推文,这样我就可以更快地阅读我的时间线。
我不喜欢的另一件事是滚动是即时的。我更喜欢在从一条推文跳到下一条推文时进行平滑滚动。即时滚动对我来说太令人困惑了。当然,如果平滑滚动太慢,这也是一个问题,因此速度必须合适。我认为 Firefox 的滚动捕捉速度非常接近我的理想速度。
对于溢出内容,如何做类似的事情?
意识到这会影响滚动捕捉,所以这里用这个代替(实际上并没有太大的变化,但仍然有效)
哇,我最近实际上对 Hacker News 的评论做了这个。我最终使用了 JavaScript,并且监听了箭头键,然后转到了列表中的下一个元素。
这看起来真的很酷,所以我在我的博客上实现了它,但发现了一些错误
在 Chrome 中,动画非常卡顿。将滚动捕捉设置为 proximity 的行为更符合预期。在 Firefox 中,它像黄油一样顺滑,更符合我的预期。
在 Firefox 中,我似乎无法滚动到页面上的最后一个项目下方。这阻止我滚动到页脚。
如果你无法安装扩展(例如,公司策略),我将这篇文章中的代码做成了一个书签
文章中提到的所有注意事项都适用。