尊重用户的运动偏好

已发表: 2022-03-10
快速总结 ↬ 近几年来,prefers prefers-reduced-motion媒体查询在所有现代浏览器中都有出色的支持。 在本文中,Michelle Barker 解释了为什么现在没有理由不使用它来使您的网站更易于访问。

在网络上使用动画时,重要的是要考虑到并非每个人都以相同的方式体验它。 对某些人来说可能感觉光滑和光滑的东西可能会令人讨厌或分散其他人的注意力 - 或者更糟糕的是,会引起生病的感觉,甚至导致癫痫发作。 具有大量运动的网站也可能对移动设备的电池寿命产生更大的影响,或者导致使用更多的数据(例如,自动播放视频将需要比静态图像更多的用户数据)。 这些只是运动繁重的网站可能不适合所有人的一些原因。

大多数新操作系统允许用户在其系统级设置中设置他们的运动偏好。 prefers-reduced-motion媒体查询(Level 5 Media Queries 规范的一部分)允许我们检测用户的系统级运动偏好,并应用尊重这一点的 CSS 样式。

prefers-reduced-motion的两个选项是reduceno-preference 。 如果用户明确设置了减少运动的偏好,我们可以在我们的 CSS 中以下列方式使用它来关闭元素的动画:

 .some-element { animation: bounce 1200ms; } @media (prefers-reduced-motion: reduce) { .some-element { animation: none; } }

相反,只有当用户没有运动偏好时,我们才能设置动画。 这样做的好处是减少了我们需要编写的代码量,并且意味着我们不太可能忘记满足用户的运动偏好:

 @media (prefers-reduced-motion: no-preference) { .some-element { animation: bounce 1200ms; } }

另一个优点是不支持prefers-reduced-motion旧浏览器将忽略该规则,只显示我们原始的、无运动元素。

哪个规则?

不像min-widthmax-width媒体查询,或多或少建立的共识是移动优先(因此支持min-width ),没有单一的“正确”方法来编写您的缩减运动样式。 由于上面列出的原因,我倾向于支持第二个示例(仅当prefers-reduced-motion: no-preference评估为 true 时才应用动画)。 Tatiana Mac 撰写了这篇出色的文章,其中涵盖了开发人员可能会考虑采用的一些方法,以及许多其他要点,包括在 web 上进行动态设计时要问的关键问题。

与往常一样,团队沟通一致的策略是确保在 Web 可访问性方面涵盖所有基础的关键。

跳跃后更多! 继续往下看↓

实际使用:将prefers-reduced-motion应用于滚动行为

除了应用(或不应用)关键帧动画或过渡之外, prefers-reduced-motion还有很多应用。 一个例子是平滑滚动。 如果我们在html元素上设置scroll-behaviour: smooth ,当用户点击页内锚链接时,他们将平滑滚动到页面上的适当位置(目前 Safari 不支持):

 html { scroll-behavior: smooth; }

不幸的是,在 CSS 中,我们现在对这种行为没有太多控制。 如果我们的内容页面很长,页面滚动速度非常快,这对于具有运动敏感性的人来说可能是一种非常不愉快的体验。 通过将其包装在媒体查询中,我们可以防止在用户具有reduced-motion偏好的情况下应用该行为:

 @media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

在 Javascript 中满足运动偏好

有时我们需要在 JavaScript 而不是 CSS 中应用动画。 我们可以类似地使用 JS 检测用户的运动偏好,使用matchMedia 。 让我们看看如何在 JS 代码中有条件地实现平滑滚动行为:

 /* Set the media query */ const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)') button.addEventListener('click', () => { /* If the media query matches, set scroll behavior variable to 'auto', otherwise set it to 'smooth' */ const behavior = prefersReducedMotion.matches ? 'auto' : 'smooth' /* When the button is clicked, the user will be scrolled to the top */ window.scrollTo({ x: 0, y: 0, behavior }) })

相同的原理可用于检测是否使用 JS 库实现运动丰富的 UI,甚至是否自己加载库。

在以下代码片段中,如果用户更喜欢减少运动,则函数会提前返回,从而避免不必要地导入大型依赖项——为用户带来性能提升。 如果它们没有设置运动偏好,那么我们可以动态导入 Greensock 动画库并初始化我们的动画。

 const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)') const loadGSAPAndInitAnimations = () => { /* If user prefers reduced motion, do nothing */ if (prefersReducedMotion.matches) return /* Otherwise, import the GSAP module and initialize animations */ import('gsap').then((object) => { const gsap = object.default /* Initialize animations with GSAP here */ }) } loadGSAPAndInitAnimations()

reduced-motion并不意味着没有运动

在为减少运动偏好设置样式时,重要的是我们仍然为用户提供有意义且可访问的指示何时发生动作。 例如,当为喜欢减少运动的用户关闭分散注意力或运动密集的悬停状态时,我们必须注意为用户悬停在元素上时提供清晰的替代样式。

以下演示显示了当用户悬停或专注于画廊项目(如果他们没有设置运动首选项)时的精细转换。 如果他们更喜欢减少运动,则过渡会更加微妙,但仍能清楚地指示悬停状态:

请参阅 Michelle Barker 的钢笔 [Pears-reduced-motion 画廊](https://codepen.io/smashingmag/pen/KKvMqaL)。

请参阅 Michelle Barker 的 pen Gallery with prefers-reduced-motion。

减少运动也不一定意味着从我们的网页中删除所有变换。 例如,一个带有小箭头图标的按钮在悬停时会移动几个像素,对于喜欢减少运动体验的人来说不太可能导致问题,并且提供比单独颜色更有用的状态变化指示。

我有时会看到开发人员通过以下方式应用缩减运动样式,这消除了所有元素上的所有过渡和动画:

 @media screen and (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; scroll-behavior: auto !important; } }

这可以说比忽略用户的运动偏好更好,但不允许我们轻松地定制元素以在必要时提供更微妙的过渡。

在下面的代码片段中,我们有一个在悬停时按比例增长的按钮。 我们正在转换颜色和比例,但喜欢减少运动的用户根本不会得到任何转换:

 button { background-color: hotpink; transition: color 300ms, background-color 300ms, transform 500ms cubic-bezier(.44, .23, .47, 1.27); } button:hover, button:focus { background-color: darkviolet; color: white; transform: scale(1.2); } @media screen and (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; scroll-behavior: auto !important; } button { /* Even though we would still like to transition the colors of our button, the following rule will have no effect */ transition: color 200ms, background-color 200ms; } button:hover, button:focus { /* Preventing the button scaling on hover */ transform: scale(1); } }

查看此演示以查看效果。 这可能并不理想,因为没有过渡的突然颜色切换可能比几百毫秒的过渡更令人不安。 这就是为什么总的来说,我通常更喜欢根据具体情况设计减少运动的样式

如果您有兴趣,这与重构的演示相同,以允许在必要时自定义转换。 它为过渡持续时间使用自定义属性,这使我们可以打开和关闭缩放过渡,而无需重写整个声明。

何时删除动画更好

Eric Bailey 在他的文章“Revisiting prefers-reduced-motion,减少运动的媒体查询”中提出了“并非每个可以访问网络的设备都可以渲染动画,或者流畅地渲染动画”的观点。 对于刷新率低的设备,可能会导致动画卡顿,实际上最好删除动画update媒体功能可用于确定:

 @media screen and (prefers-reduced-motion: reduce), (update: slow) { * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; } }

请务必阅读 Eric 建议的完整文章,因为他是可访问性领域的一流人物。

所有部分的总和

当如此紧密地关注组件级 CSS 时,牢记整体页面设计非常重要。 在组件级别看似无害的动画在整个页面中重复时可能会产生更大的影响,并且是许多移动部分之一。

在 Tatiana 的文章中,她建议在单个 CSS 文件中组织动画(使用prefers-reduced-motion ),只有在(prefers-reduced-motion: no-preference)评估为 true 时才能加载该文件。 查看我们所有动画的总和可以帮助我们将访问整个站点的体验可视化,并相应地调整我们的减动画样式。

显式运动切换

虽然prefers-reduced-motion很有用,但它确实有一个缺点,即只迎合那些在其系统设置中了解该功能的用户。 许多用户不了解此设置,而其他用户可能正在使用借来的计算机,而无法访问系统级设置。 尽管如此,其他人可能对绝大多数网站的运动感到满意,但发现大量使用运动的网站难以忍受。

仅仅为了访问一个站点就必须调整系统偏好可能很烦人。 由于这些原因,在某些情况下,最好在站点本身上提供一个显式控件来切换运动 on 和 off 。 我们可以用 JS 来实现。

下面的演示有几个圆圈在背景中漂移。 初始动画样式由用户的系统偏好决定(使用prefers-reduced-motion ),但是,用户可以通过按钮打开或关闭运动。 这为body添加了一个类,我们可以使用它来根据所选偏好设置样式。 作为奖励,动作偏好的选择也保存在本地存储中——所以当用户下次访问时它会被“记住”。

请参阅 Michelle Barker 的 Pen [Reduced-motion toggle](https://codepen.io/smashingmag/pen/porEQLB)。

请参阅 Michelle Barker 的 Pen Reduced-motion 切换。

自定义属性

演示中的一个功能是切换设置了一个自定义属性--playState ,我们可以使用它来播放或暂停动画。 如果您需要一次暂停或播放多个动画,这可能特别方便。 首先,我们将播放状态设置为paused

 .circle { animation-play-state: var(--playState, paused); }

如果用户在他们的系统设置中设置了减少运动的偏好,我们可以将播放状态设置为running

 @media (prefers-reduced-motion: no-preference) { body { --playState: running; } }

注意:body上设置这个,而不是在单个元素上,意味着可以继承自定义属性。

当用户单击切换时,自定义属性会在body上更新,这将切换使用它的任何实例:

 // This will pause all animations that use the `--playState` custom property document.body.style.setProperty('--playState', 'paused')

在所有情况下,这可能不是理想的解决方案,但一个优点是当用户单击切换时动画只是暂停,而不是跳回其初始状态,这可能会很刺耳。

特别感谢 Scott O'Hara 就改进切换的可访问性提出的建议。 他让我知道,一些屏幕阅读器不会宣布更新的按钮文本,当用户单击按钮时会更改,而是建议在按钮上使用role="switch" ,并在单击时将aria-checked切换为onoff

视频分量

在某些情况下,在组件级别切换运动可能是更好的选择。 获取具有自动播放视频背景的网页。 我们应该确保视频不会为喜欢减少运动的用户自动播放,但我们仍然应该为他们提供一种他们选择时播放视频的方式。 (有些人可能会争辩说我们应该避免完全停止自动播放视频,但我们并不总能赢得这场战斗!)同样,如果视频被设置为为没有明确偏好的用户自动播放,我们还应该为他们提供一种方法暂停视频。

这个演示展示了我们如何在用户没有明确的运动偏好时设置自动播放属性,实现自定义播放/暂停按钮以允许他们也切换播放,无论偏好如何:

请参阅 Michelle Barker 的 Pen [带有运动偏好的视频](https://codepen.io/smashingmag/pen/qBXNjqR)。

请参阅 Michelle Barker 的具有运动偏好的 Pen Video。

(我随后看到了 Scott O'Hara 的这篇文章,详细介绍了这个确切的用例。)

使用<picture>元素

Chris Coyier 写了一篇有趣的文章,结合了几种技术来根据用户的运动偏好加载不同的媒体源。 这很酷,因为这意味着对于喜欢减少运动的用户来说,甚至不会下载更大的 GIF 文件。 据我所知,不利的一面是,一旦下载了文件,用户就无法切换回无运动替代方案。

我创建了添加此选项的演示的修改版本。 (在您的系统偏好设置中打开reduced-motion以查看它的实际效果。)不幸的是,在 Chrome 中的动画和无运动选项之间切换时,似乎每次都重新下载 GIF 文件,而在其它浏览器:

见笔【更喜欢还原运动技术 PLUS! [分叉]](https://codepen.io/smashingmag/pen/porbPXG) 米歇尔·巴克。

请参阅 Pen Preferred Reduction Motion Technique PLUS! [分叉] 米歇尔·巴克。

尽管如此,这种技术似乎是一种更尊重的显示 GIF 的方式,这可能会让用户感到沮丧。

浏览器支持和最终想法

几年前, prefers-reduced-motion在所有现代浏览器中都有出色的支持。 正如我们所看到的,通过采用减少运动优先的方法,不支持的浏览器将简单地获得reduced-motion后备。 今天没有理由不使用它来使您的网站更易于访问。

自定义切换绝对有一席之地,并且可以极大地改善不了解此设置或其作用的用户的体验。 用户的缺点是不一致 - 如果每个开发人员都被迫提出自己的解决方案,用户需要在每个网站的不同位置寻找动作切换。

感觉这里缺少的层是browsers 。 我很想看到浏览器实现reduced-motion切换,用户可以轻松访问的地方,这样人们就知道在哪里可以找到它,而不管他们正在浏览的网站是什么。 它也可能会鼓励开发人员花更多时间确保运动可访问性。

相关资源

  • 5 级媒体查询规范,万维网联盟 (W3C)
  • prefers-reduced-motion ,MDN Web Docs,Mozilla
  • 减少运动灵敏度的设计,Val Head,Smashing Magazine
  • 采用无运动优先的动画方法,Tatiana Mac
  • 缩减动画技术,Take 2,Chris Coyier,CSS-Tricks
  • 重温prefers-reduced-motion , The Reduced Motion Media Query, Eric Bailey, CSS-Tricks
  • 减少运动以提高可访问性,Lindsey Kopacz