正确响应 prefers-reduced-motion 需精准使用 @media (prefers-reduced-motion: reduce),降级 animation/transition 时保留 0.01s 过渡、避免 !important 粗暴覆盖,同步处理 js 动画与第三方库,并真机测试验证。

用户开了“减少动画”系统偏好时,prefers-reduced-motion 会生效;但直接全局关掉所有动画,反而会让模态框失焦、菜单无法滚动、按钮反馈消失——这不是无障碍,是功能破坏。
怎么写正确的 @media (prefers-reduced-motion: reduce) 规则
别写成 (prefers-reduced-motion: true) 或漏引号,它只接受 reduce 和 no-preference 两个字面值。媒体查询必须精确匹配:
-
@media (prefers-reduced-motion: reduce)是唯一有效的写法 - 不要用
!important粗暴覆盖所有animation,而是有选择地降级 - 重点重置
animation-duration、transition-duration、animation-iteration-count,而非直接设animation: none - 保留
opacity的极短过渡(如0.01s),避免元素突兀闪现
为什么不能只禁 animation 却放任 transition
很多交互依赖 :hover、:focus 或 JS 切换 class 触发的 transition,比如下拉菜单展开靠 max-height 过渡、按钮按压靠 transform 缓动。若只关 animation,这些仍会平滑运动,违背用户偏好。
- 必须同时处理
transition:统一设transition-duration: 0.01s !important - 对含
transform的过渡要额外小心——浏览器默认插值,即使 duration 为 0 也可能有微动;加transform: none !important强制归零 - 避免用
visibility: hidden+opacity: 0组合做隐藏,易被读屏器误判;改用display: none或hidden属性更稳妥
JS 动画怎么响应 prefers-reduced-motion
CSS 媒体查询管不到 requestAnimationFrame、Canvas 绘图或 GSAP 动画。必须用 JS 主动监听并跳过动画逻辑,而不是暂停后恢复。
- 用
window.matchMedia("(prefers-reduced-motion: reduce)")获取初始状态 - 监听
change事件,避免只检查一次就不再更新 - 轮播组件中,不要
carousel.pause()再carousel.resume(),而应:if (!reducedMotion) { startAutoSlide(); } - 对
element.animate(),直接不调用;对 inline style 动画,改用element.style.opacity = "1"瞬时设终态
测试时最容易忽略的三个点
真机测试比 DevTools 模拟更可靠,尤其 iOS Safari 对该特性响应更严格。
- Chrome DevTools 的 “Simulate CSS prefers-reduced-motion” 只影响 CSS,不触发 JS 中的
matchMedia监听——需手动刷新页面或在控制台重运行监听逻辑 - 第三方 UI 库(如 Bootstrap、Element Plus)自带的动画常绕过你的媒体查询,得单独给它们的 class 加降级规则,例如
.modal.fade、.el-collapse-transition - 自定义滚动条、
scroll-behavior: smooth、scroll-snap等也受该偏好影响,但容易被遗漏;建议统一加@media (prefers-reduced-motion: reduce) { * { scroll-behavior: auto; } }
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











