@media (prefers-reduced-motion: reduce) 是唯一可靠入口,浏览器仅识别 reduce 和 no-preference 两个规范值,true 等写法均无效;需分层降级动画,禁用纯视觉动画、保留结构过渡、重置 hover/focus 动效,并手动监听 js 动画。

@media (prefers-reduced-motion: reduce) 是唯一可靠入口,别用 JS 判断或写 prefers-reduced-motion: true
为什么 @media (prefers-reduced-motion: true) 完全不生效
浏览器只认两个规范值:reduce 和 no-preference。写成 true、1、reduced 或漏掉英文引号(如 reduce 不加引号),整条媒体查询都会被忽略——DevTools 里对应样式块会灰掉,毫无作用。iOS Safari 尤其严格,必须是 "reduce" 全小写带双引号。
怎么写 CSS 才既禁动画又不破坏功能
粗暴加 * { animation: none !important; transition: none !important; } 会让下拉菜单突然撑开、模态框闪现、滚动容器失灵。正确做法是分层降级:
- 纯视觉动画(loading spinner、背景色轮播):用
animation: none彻底停掉 - 结构过渡(菜单展开、折叠面板):保留
transition: max-height 0.01s linear或opacity 0.01s,避免布局突变 - hover/focus 动效:显式重置 transform,例如
.btn:hover { transform: scale(1); transition: none; } - 强制瞬时切换:对关键容器加
transform: none !important; opacity: 1 !important;,再交由 JS 控制显隐逻辑
JS 动画必须手动响应,CSS 媒体查询管不到它
@media 只影响 CSS 层动画,requestAnimationFrame、gsap.to()、element.animate() 等完全不受控。必须主动监听并降级:
- 初始化时获取状态:
const motionQuery = window.matchMedia("(prefers-reduced-motion: reduce)") - 监听变更:
motionQuery.addEventListener("change", handleMotionChange)(Safari 14+ 支持) - 动效启动前判断:
if (!motionQuery.matches) { startParallax() },而不是运行中暂停 - 骨架屏、轮播图等场景:直接设终态,例如
el.style.opacity = "1"; el.style.transform = "none";
测试时最容易漏的三件事
仅在 Chrome DevTools Rendering 面板勾选 “Reduced motion” 不够:
- iOS Safari 对语法更敏感,某些自定义滚动条动画会被静音,必须真机验证
- 系统设置路径差异大:macOS 是「辅助功能 → 显示 → 降低动态效果」,Windows 是「辅助功能 → 视觉效果 → 在 Windows 中显示动画」,iOS 是「辅助功能 → 动作 → 减少动态」
- 第三方组件(如 Ant Design)里的内联动画,只有 CSS 媒体查询能兜住,JS 监听无法覆盖
真正难的不是写对那行 @media,而是把所有含 transition、animation、transform、opacity 的地方都系统性地筛一遍,并区分哪些该删、哪些该压到毫秒级、哪些必须靠 JS 补位——漏掉一个 hover 动效,就可能让低配设备用户卡顿或眩晕。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











