首选减压:有时运动越少

Preferreds-reduced-motion 媒体查询可检测用户是否已请求操作系统尽可能减少其使用的动画或运动量。

并非每个人都喜欢装饰性动画或过渡,并且一些用户在面对视差滚动、缩放效果等时会直接产生晕动病。借助用户偏好设置媒体查询 prefers-reduced-motion,您可以为已表现出这种偏好设置的用户设计出网站减少动作的变体。

浏览器支持

  • 74
  • 79
  • 63
  • 10.1

来源

现实生活和网络上的动作过多

前几天,我和孩子们一起滑冰。今天天气不错,阳光明媚,溜冰场上挤满了人 ⛸。唯一的问题是:我不能很好地与人相处。有如此多的移动目标,我都无法专注于任何事情,最终会迷失方向,并有一种彻底的视觉过载感,几乎就像凝视着蚂蚁 🐜?。

一群大脚溜冰的人。
现实中的视觉过载。

这种情况偶尔会发生在网络上:闪烁的广告、奇特的视差效果、令人惊叹的揭秘动画、自动播放视频等等,网络有时可能会让人感到无所适从...令人欣慰的是,这与在现实生活中不同,是有解决方案的。借助 CSS 媒体查询 prefers-reduced-motion,开发者可以为喜欢减少动态的用户创建网页变体。这可能包括各种操作,从禁止自动播放视频到停用某些纯装饰性效果,再到针对特定用户彻底重新设计网页,不一而足。

在深入了解该功能之前,我们先回过头,想一想 Web 上有哪些动画。如果需要,您还可以跳过背景信息,直接查看下面的技术详情

网页上的动画

动画通常用于向用户提供反馈,例如让用户知道某项操作已收到且正在处理。例如,在购物网站上,可通过动画将产品“飞”入虚拟购物车,并以图标的形式显示在网站右上角。

另一个使用场景涉及结合使用骨架屏幕、情境元数据和低质量图片预览,利用动作来打击用户感知,从而占用大量用户的时间并使整个体验获得更快速的体验。这样做是为了让用户了解即将发生的内容,同时尽快加载内容。

最后还有装饰效果,如动画渐变、视差滚动、背景视频等。虽然许多用户喜欢此类动画,但有些用户不喜欢此类动画,因为它们感觉分心或拖慢了速度。在最糟糕的情况下,用户甚至可能会像在现实生活中一样遭受晕动病的折磨,因此对于这些用户来说,减少动画是一种必要的医疗手段

运动触发的前片声谱障碍

有些用户会因动画内容而感到分心或恶心。例如,当与滚动相关联的主要元素以外的元素大量移动时,滚动动画可能会导致前庭观众紊乱。例如,视差滚动动画可能会导致前景元素混乱,因为背景元素的移动速率与前景元素的速度不同。前庭(内耳)紊乱反应包括头晕、恶心和偏头痛,有时需要卧床休息才能恢复。

在操作系统上移除动态效果

长期以来,许多操作系统都有无障碍设置,用于指定减少动作的偏好设置。以下屏幕截图显示了 macOS Mojave 的 Reduce motion 偏好设置和 Android Pie 的 Remove animation 偏好设置。勾选后,这些偏好设置会导致操作系统不使用装饰效果,例如应用启动动画。应用本身可以而且也应该遵循此设置,并移除所有不必要的动画。

macOS 设置屏幕的屏幕截图,其中选中了“减少动态”复选框。
Android 设置屏幕的屏幕截图,其中选中了“移除动画”复选框。

移除网页上的动画

媒体查询级别 5 也会将减少动作的用户偏好设置带到网络上。借助媒体查询,作者可以独立于呈现的文档来测试和查询用户代理或显示设备的值或功能。媒体查询 prefers-reduced-motion 用于检测用户是否设置了操作系统偏好设置来最大限度地减少其使用的动画或动作量。它可能有两个可能的值:

  • no-preference:表示用户在底层操作系统中没有偏好。此关键字值在布尔值上下文中的求值结果为 false
  • reduce:表示用户已设置操作系统偏好设置,指示界面应尽可能减少移动或动画,最好是移除所有非基本移动。

处理来自 CSS 和 JavaScript 上下文的媒体查询

与所有媒体查询一样,可以从 CSS 上下文和 JavaScript 上下文检查 prefers-reduced-motion

举个例子,假设我有一个重要的注册按钮,并希望用户点击该按钮。我可以定义一个引人注目的“振动”动画,但作为一名优秀的网络用户,我只会为那些明确同意使用动画的用户播放动画,而不是为其他所有人播放,这些用户可能是选择停用动画的用户,也可能是使用无法理解媒体查询的浏览器的用户。

/*
  If the user has expressed their preference for
  reduced motion, then don't use animations on buttons.
*/
@media (prefers-reduced-motion: reduce) {
  button {
    animation: none;
  }
}

/*
  If the browser understands the media query and the user
  explicitly hasn't set a preference, then use animations on buttons.
*/
@media (prefers-reduced-motion: no-preference) {
  button {
    /* `vibrate` keyframes are defined elsewhere */
    animation: vibrate 0.3s linear infinite both;
  }
}

为了说明如何通过 JavaScript 使用 prefers-reduced-motion,假设我使用 Web Animations API 定义了一个复杂动画。虽然当用户偏好设置发生更改时浏览器会动态触发 CSS 规则,但对于 JavaScript 动画,我必须自行监听更改,然后手动停止可能正在播放的动画(如果用户允许,请重新启动):

const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
mediaQuery.addEventListener('change', () => {
  console.log(mediaQuery.media, mediaQuery.matches);
  // Stop JavaScript-based animations.
});

请注意,实际媒体查询前后必须加上括号:

错误做法
window.matchMedia('prefers-reduced-motion: reduce');
正确做法
window.matchMedia('(prefers-reduced-motion: reduce)');

处理来自 <picture> 上下文的媒体查询

一个有趣的用例是使动画 AVIF、WebP 或 GIF 的播放依赖于 media 属性。如果 (prefers-reduced-motion: no-preference) 的求值结果为 true,就可以放心显示动画版本,否则显示静态版本:

<picture>
  <!-- Animated versions. -->
  <source
    srcset="nyancat.avifs"
    type="image/avif"
    media="(prefers-reduced-motion: no-preference)"
  />
  <source
    srcset="nyancat.gif"
    type="image/gif"
    media="(prefers-reduced-motion: no-preference)"
  />
  <!-- Static versions. -->
  <img src="nyancat.png" alt="Nyan cat" width="250" height="250" />
</picture>

请参见下面的示例。尝试切换设备的动作偏好设置,查看不同之处。

彩虹猫

在请求时发现用户的偏好设置

借助 Sec-CH-Prefers-Reduced-Motion 客户端提示标头,网站可以选择在请求时获取用户的动作偏好设置,以便服务器出于性能方面的原因内嵌正确的 CSS。

演示

我根据 Rogério Vicente 的精彩 🐈? HTTP status cats 创建了一个小演示。首先,花点时间欣赏一下这个笑话,很有趣,我会等着现在您回来了,我来介绍一下演示。当您向下滚动时,每个 HTTP 状态猫会从右侧或左侧交替显示。这是一个非常流畅的 60 FPS 动画,但如上所述,有些用户可能不喜欢它,甚至会因此产生晕动症,因此该演示被编程为遵循 prefers-reduced-motion。这甚至可以动态运作,因此用户可以即时更改其偏好设置,而无需重新加载。如果用户更喜欢减少动作,不必要的揭示动画就会消失,只留下常规的滚动动作。下面的抓屏展示了实际演示:

prefers-reduced-motion 演示应用的视频

总结

尊重用户偏好设置对现代网站来说至关重要,浏览器为了支持 Web 开发者而推出越来越多的功能。另一个已发布的示例是 prefers-color-scheme,它可检测用户是偏爱浅色还是深色配色方案。您可以在我的文章 Hello Darkness, My Old Friend 🌒? 这篇文章中阅读关于 prefers-color-scheme 的所有内容。

CSS 工作组目前正在对更多用户偏好媒体查询进行标准化,例如 prefers-reduced-transparency(检测用户是否更喜欢降低透明度)、prefers-contrast(检测用户是否已请求系统提高或降低相邻颜色之间的对比度)和 inverted-colors(检测用户是否更喜欢反色)。

(额外知识)在所有网站上强制减少移动

并非所有网站都会使用 prefers-reduced-motion,也可能不是足够符合您的喜好。 如果出于任何原因,您确实想在所有网站上设置定格动画,您完全可以。要实现这一点,一种方法是将包含以下 CSS 的样式表注入您访问的每个网页。市面上的多个浏览器扩展程序(使用时需自行承担风险!)可让您实现此功能。

@media (prefers-reduced-motion: reduce) {
  *,
  ::before,
  ::after {
    animation-delay: -1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    background-attachment: initial !important;
    scroll-behavior: auto !important;
    transition-duration: 1ms !important;
    transition-delay: 1ms !important;
  }
}

其工作原理是,上述 CSS 会将所有动画和过渡的时长替换成非常短的时间,使其不再被注意到。由于某些网站需要运行动画才能正常运行(或许是因为某个步骤取决于 animationend 事件的触发),因此更极端的 animation: none !important; 方法将不起作用。即使是上述黑客行为也不能保证在所有网站上都能成功(例如,它不能通过 Web Animations API 发起的定格动画),因此请务必在发现网站有破坏时将其停用。

致谢

此外,我们还为在 Chrome 中实现了 prefers-reduced-motionStephen McGruer 以及 Rob Dodson 共同阅读了这篇文章。主打图片,由 Hannah Cauhepe 在 Un 创办网站上使用。