应使用@media (prefers-reduced-motion: reduce)而非true,因该媒体查询仅支持reduce和no-preference;需分层控制动画:停用纯视觉动画、保留结构过渡、压缩关键帧时长、禁用平滑滚动,并监听mediaquery变化降级js动画,同时强制重置transform和opacity以防止隐式插值。

直接用 @media (prefers-reduced-motion: reduce) 覆盖关键动画属性,而不是全局清空或依赖 JS 判断——后者容易漏掉 inline style、第三方组件或 requestAnimationFrame 动画。
为什么不能写 @media (prefers-reduced-motion: true)
语法错误。该媒体查询只接受两个标准值:reduce 和 no-preference,没有布尔类型。写成 true 会导致整个媒体查询失效,样式完全不加载。macOS、Windows 10+、iOS 开启“减少运动”后触发的都是 reduce,不是布尔值。
animation 和 transition 怎么关才不破坏功能
粗暴加 * { animation: none !important; transition: none !important; } 会让下拉菜单突然撑开、模态框闪现、滚动容器失灵——因为结构依赖过渡维持状态。正确做法是分层控制:
- 对纯视觉动画(如 loading spinner),用
animation: none !important彻底停掉 - 对结构型过渡(如
max-height展开菜单),单独保留transition: max-height 0.1s linear,避免内容被截断 - 用
animation-duration: 0.01ms !important替代animation: none,保留关键帧逻辑但压缩到几乎瞬时 - 禁用平滑滚动:
html { scroll-behavior: auto !important; }
JS 动画怎么响应偏好变化
CSS 媒体查询管不到 requestAnimationFrame、GSAP、轮播组件或骨架屏的自动播放。必须手动监听并降级:
- 初始化时获取状态:
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";
最容易被忽略的是 transform 和 opacity 的隐式插值——即使没写 transition,JS 直接改这两个属性,浏览器仍会平滑过渡。得在媒体查询里强制 transform: none !important; opacity: 1 !important;,再交由 JS 控制显隐逻辑。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











