先记住这个答案
在媒体查询中写入 @media (prefers-reduced-motion: reduce) 可为偏好用户提供静态或低动态样式。用户开启系统“减少动态效果”后,浏览器将该特性值设为 reduce,否则为 no-preference。通常将停止大幅位移动画或替换为透明度变化,并确保 reduce 规则在普通规则之后出现以覆盖默认样式。
- 通过系统设置驱动 CSS 动画开关
- 仅覆盖 CSS 触发的动画,JS 需另处理
- reduce 可作为布尔条件简写
媒体查询如何读取系统偏好
操作系统提供的“减少动态效果”开关会经浏览器映射为媒体特性。当用户开启后,prefers-reduced-motion 的值为 reduce,未开启则为 no-preference。CSS 中可以使用 @media (prefers-reduced-motion: reduce) 匹配该偏好,或简写为 @media (prefers-reduced-motion) 。这种媒体查询属于用户偏好级,不依赖视口或设备类型。
关键在于层叠顺序:该分支内的规则如果与默认规则同特异性,则需放在其后才会生效。典型做法是在文件末尾集中定义 reduce 样式,确保能覆盖前面声明的动画属性。此外,这种写法也可与 and 组合多个条件,例如同时匹配窄屏和 reduce 偏好。
自动轮播横幅的降级处理
某产品首页有多张图自动轮播,通过 CSS 让内容横向平移实现平滑切换。同时页面有漂浮雪花装饰动画,对前庭障碍用户容易引发眩晕。现在需要响应 reduce 偏好,但轮播内容仍需展示给用户。处理方案:保留轮播的逻辑切换,但用淡入淡出取代横向位移,减少大范围视觉运动。
实现时,为普通状态书写横向 slide 动画,再在 reduce 分支用 opacity 动画覆盖。若轮播切图由 JS 控制,CSS 无法暂停定时器,需要额外用 matchMedia('(prefers-reduced-motion: reduce)') 监听,动态调整自动切换频率或改为手动按钮。最终结果满足无障碍需求但保留了信息展示。
.banner {
animation: slide 6s linear infinite;
}
@keyframes slide {
0% { transform: translateX(0); }
100% { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
.banner {
animation: fade 8s ease-in-out infinite;
}
}
@keyframes fade {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}这是一个纯 CSS 片段,需在现代浏览器中运行。reduce 分支替换了动画函数,使页面只在原位置淡入淡出而非平移,满足减少运动的需求。
失效条件与开发代价
该媒体特性只作用于 CSS 样式层。若动画由 JavaScript 通过 requestAnimationFrame 驱动,或直接修改元素 style 属性,prefers-reduced-motion 不会自动拦截。例如基于 JS 的视差滚动库、粒子特效,它们无法被媒体查询关闭,必须依赖 matchMedia 手动接管,否则用户仍会看到大幅运动的元素。
另一边界是用户可能没有开启该偏好,但依然对闪烁敏感。此时 reduce 分支不会生效,需要开发者主动控制动画数量与强度。为覆盖这一情况,通常将动画设计为从第一天就不过度夸张,或提供页面内的“减少动画”开关。额外代价是增加少量判断代码,但能避免体验分裂,整体收益大于维护成本。
容易答错的地方
- 误认为 reduce 等于完全无动画
- prefers-reduced-motion 仅表示用户希望减少不必要的运动,而非禁止一切变化。内容仍可通过透明度切换、静态展示或简单交错呈现。若直接隐藏所有动画导致信息缺失,并不符合无障碍初衷,应提供合适的替代呈现。
- 忽略 JS 驱动的动画
- CSS 媒体查询不会影响通过 JS 设定动画帧或 rAF 循环的逻辑。常见错误是只写了 @media (prefers-reduced-motion: reduce) 关闭 CSS animation,但页面上 JS 轮播仍继续自动跳转。解决方案是用 matchMedia 监听偏好,并相应地暂停或延长间隔,同时清理监听器避免泄漏。
面试官还会怎么问?
能否同时检测 prefers-reduced-motion 与深色调偏好?
可以。媒体查询支持 and 连接多个特性,例如 @media (prefers-reduced-motion: reduce) and (prefers-color-scheme: dark) 同时匹配两种条件。这样能针对不同组合提供定制样式,但需注意优先级与源顺序。
用户未设置时是否必须写 no-preference?
不必。no-preference 是默认值,当用户未开启减少动态时即生效。若显式书写 @media (prefers-reduced-motion: no-preference) 会匹配默认状态,但通常没有实际意义,因为普通样式已在默认情况下应用。系统中没有单独的“无偏好”选项,因此无需区分显式无偏好与未声明。
在浏览器开发者工具中如何模拟 reduce?
多数浏览器的 DevTools 提供“模拟 CSS 媒体特性”功能,可在 Rendering 或 Media 面板中切换 prefers-reduced-motion 为 reduce。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。