(prefers-reduced-motion: reduce) 是唯一有效值,必须全小写加双引号;JS 监听易漏动画源,CSS 层拦截才可靠;降级需分层处理动画与过渡,避免布局突变,且 transition 和 animation 必须同时覆盖。

prefers-reduced-motion媒体查询怎么写才有效
浏览器只认 (prefers-reduced-motion: reduce) 和 (prefers-reduced-motion: no-preference) 两个值,写成 true、1、reduced 或漏掉引号(如 reduce 不加双引号)都会让整条媒体查询失效——DevTools 里对应样式块会直接灰掉,毫无作用。iOS Safari 尤其严格,必须是全小写带双引号的 "reduce"。
为什么不能只靠 JS 监听来关动画
JS 用 window.matchMedia('(prefers-reduced-motion: reduce)') 监听再手动删 class 或重置样式,容易漏掉三类情况:
-
@keyframes在 CSS 文件里已声明,哪怕没被调用,浏览器仍会解析 - 第三方组件或内联
style里的动画,JS 没法覆盖 - 首屏加载时动画已触发,而 JS 还没执行完
真正可靠的起点是 CSS 层面拦截:浏览器在解析样式时就跳过或降级,从源头避免动画启动。
怎么写降级规则才不破坏功能
粗暴写 * { animation: none !important; transition: none !important; } 会让下拉菜单突然撑开、模态框闪现、滚动容器失灵。正确做法是分层处理:
立即学习“前端免费学习笔记(深入)”;
- 纯视觉动画(loading spinner、背景轮播)→ 用
animation: none彻底停掉 - 结构过渡(菜单展开、折叠面板)→ 改用
transition: max-height 0.01s linear或opacity 0.01s,避免布局突变 - hover/focus 动效 → 显式重置,例如
.btn:hover { transform: scale(1); transition: none; } - 关键容器需瞬时切换 → 加
transform: none !important; opacity: 1 !important;,再交由 JS 控制显隐逻辑
transition 和 animation 都得单独覆盖
很多人只关 animation 却漏掉 transition,结果 hover 时仍有延迟位移或颜色渐变。降级规则里这两者必须同时处理:
@media (prefers-reduced-motion: reduce) {
.card, .dropdown, .modal {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}注意:0.01ms 是最小非零值,比 0s 更稳妥(某些旧版 Safari 对 0s 处理异常);!important 必须加,否则易被组件库或内联样式覆盖;生产环境别用 * 兜底,应缩小选择器范围。
真正难的不是写出那行 @media,而是把所有含 transition 和 animation 的地方都找出来——包括第三方组件、CSS-in-JS、伪类状态、甚至 :focus-visible 触发的动效。


















