首选减压:有时运动越少

Preferreds-Reduced-motion 媒体查询可检测用户是否已要求操作系统最大限度地减少其使用的动画或动作量。

并非每个人都喜欢装饰性动画或转场效果,并且有些用户在面对视差滚动、缩放效果等时直觉感到晕车。借助用户偏好设置媒体查询 prefers-reduced-motion,您可以为已表达过这种偏好的用户设计网站动画形式的简化变体。

浏览器支持

  • 74
  • 79
  • 63
  • 10.1

来源

现实生活和网页中的动作过多

前几天,我和孩子们一起去滑冰。那天天气不错,阳光明媚,溜冰场挤满了人 ⛸。唯一的问题是:我不太适应人群。我有很多移动的目标,无法专注于任何事情,最终迷失方向,感觉完全有视觉冲击力,就像盯着蚂蚁 🐜? 一样。

大量的溜冰爱好者。
现实生活中的视觉过载。

有时,网络上也可能出现相同的情况:闪烁的广告、华丽的视差效果、出人意料的揭秘动画、自动播放的视频等等,有时可能会让人应接不暇...值得庆幸的是,与现实生活不同的是,有解决方案可以做到这一点。借助 CSS 媒体查询 prefers-reduced-motion,开发者可以为那些更喜欢运动减速的用户创建页面变体。这可能包括禁止自动播放视频、停用某些纯装饰效果,以及为特定用户彻底重新设计网页。

在深入介绍此功能之前,我们先回过头来想一想,动画在 Web 应用中的用途。如果需要,您还可以跳过背景信息,直接查看下面的技术细节。

Web 上的动画

动画经常用于向用户提供反馈,例如,告知用户其已收到操作并正在处理。例如,在购物网站上,可以为产品添加动画效果以“飞”进虚拟购物车,并在网站右上角显示为一个图标。

另一个使用场景涉及通过结合使用骨架屏幕、上下文元数据和低质量图片预览,使用动作来侵入用户感知,从而占用大量用户的时间并使整个体验更快。其理念是为用户提供有关即将发生的内容的背景信息,同时尽快加载内容。

最后还有装饰效果,例如动画渐变、视差滚动、背景视频等。虽然许多用户喜欢此类动画,但也有一些用户不喜欢,因为它们会让用户感到分心或拖慢速度。在最糟糕的情况下,用户甚至可能像在现实生活中那样经历晕动病,因此对于此类用户而言,减少动画是一项医疗必要性

运动诱发前庭频谱障碍

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

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

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

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

在网页上移除动态效果

媒体查询级别 5 也会为 Web 应用带来减少动作的用户偏好。借助媒体查询,作者可以测试和查询用户代理或显示设备的值或功能,与呈现的文档无关。媒体查询 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> 上下文中的媒体查询

一个有趣的用例是,根据 media 属性播放动画 AVIF、WebP 或 GIF。如果 (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 发起的定格动画),因此请务必在发现损坏时将其停用。

致谢

Stephen McGruer 在 Chrome 中实现了 prefers-reduced-motion 并与 Rob Dodson 一起,对此我们表示诚挚的感谢。主打图片:Hannah Cauhepe on Unsplash。