功能渐进增强是从核心功能出发确保基础交互在任何环境可用,再用@supports等CSS能力检测分层增强;降级样式写外部,增强样式写内部;:focus-visible、:has()等伪类天然支持回退;prefers-reduced-motion需用@media直接控制动效。

什么是功能渐进增强,不是样式叠加
渐进增强不是“先写个简陋版再加CSS特效”,而是从核心功能出发,让基础交互在任何环境都能运行,再用CSS检测能力去分层增强。比如表单验证,必须先保证 required 属性生效、提交逻辑可用,再用 :valid / :invalid 做视觉反馈——否则关掉JS或用老浏览器时,用户根本不知道哪错了。
@supports 是唯一可靠的CSS能力探测手段
别用浏览器UA判断,也别靠JS查 document.body.style.clipPath 这类属性是否存在。CSS原生的 @supports 才是语义正确、可被CSS引擎优化的方案。它能真正反映当前渲染引擎是否支持某个声明,且支持嵌套和逻辑组合。
常见误用:@supports (display: grid) 看似合理,但IE11不支持 @supports 本身,会直接跳过整段规则——这意味着你得把栅格布局的降级方案(如 float 或 inline-block)写在 @supports 外面,增强部分才包进去。
实操建议:
- 降级样式写在
@supports外部,增强样式写在里面 - 用
and/not组合多个条件,比如@supports (display: grid) and (gap: 1rem) - 避免检测太细的语法糖,如
@supports (inset: 0)—— Safari 15.4+ 才支持,但很多场景用top/right/bottom/left更稳
伪类与属性选择器本身就是渐进增强的天然载体
:focus-visible、:has()、[data-js] 这些不是“炫技开关”,而是功能分层的锚点。它们的存在与否,直接对应着某项交互能力是否就绪。
比如用 :focus-visible 替代全局 :focus,就能在键盘导航时显示焦点环,鼠标点击时不干扰视觉——但旧浏览器会忽略这个伪类,自动回退到传统 :focus 行为,无需额外JS干预。
又比如 :has() 可以实现“父元素根据子状态变色”,但目前仅Chrome 105+ / Safari 15.4+ 支持。这时候你应该:
- 先用JS打
data-state="loaded"这类标记,配合[data-state="loaded"] .item做兼容 - 再用
@supports selector(:has(*))把:has()版本覆盖上去 - 绝不把关键布局或可访问性依赖
:has(),它只是锦上添花
媒体查询 + prefers-reduced-motion 是最常被漏掉的能力分支
很多人以为渐进增强只关乎“新功能有没有”,其实“用户要不要”同样关键。比如动画:默认用 transition,但遇到系统开启“减少运动”偏好时,应该立即切断所有非必要动效——这不是降级,是尊重。
错误做法:只在JS里监听 prefers-reduced-motion 并移除class,导致首次渲染仍闪一下。
正确做法:
- 用
@media (prefers-reduced-motion: reduce)直接重置transition、animation等属性为none - 把关键交互动效(如按钮按压反馈)保留在
prefers-reduced-motion: no-preference分支里 - 注意 Safari 对
prefers-reduced-motion的支持从 14 开始,但早期版本会忽略整个媒体查询,所以默认样式必须是安全的
复杂点在于,这些能力检测不是孤立的:一个组件可能同时涉及 @supports、@media、属性选择器三层叠加。最容易被忽略的是——当多层嵌套时,CSS优先级和层叠顺序会悄悄改变行为,得靠浏览器开发者工具的“Computed”面板逐条确认最终生效值,不能只看源码顺序。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











