CSS 特性查询
容器查询问的是 父级 有多宽。媒体查询盯着 视口。特性查询问的是另一件事:这个 浏览器 懂这段 CSS 吗?用 @supports,你先交付可靠的基础样式,再只在引擎能处理的地方解锁现代布局或选择器。
渐进增强,不是赌博
特性查询是一道 能力闸门。你不会删掉旧样式——而是保留处处可用的布局,再在 @supports 里加上更丰富的一层,前提是引擎能解析你需要的特性(例如 display: grid,或 flex 上的 gap)。
基本的 @supports
常见写法测试一对 属性–值。浏览器能处理该声明时,块内规则才会生效:
.card-list {
display: block;
}
.card-list .card {
margin-bottom: 1rem;
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 0.75rem;
background: #fff;
}
@supports (display: grid) {
.card-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
gap: 1rem;
}
.card-list .card {
margin-bottom: 0;
}
}
块外,卡片靠简单外边距纵向堆叠。进入 @supports (display: grid) 后,同一列表变成自适应网格——旧引擎保留堆叠,新引擎拿到 grid。
组合条件:and、or、not
你可以同时要求多项特性、接受任一替代项,或把测试反过来:
@supports (display: grid) and (gap: 1rem) {
.toolbar {
display: grid;
grid-auto-flow: column;
gap: 0.75rem;
align-items: center;
}
}
@supports (display: flex) or (display: grid) {
.cluster {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
}
@supports not (display: grid) {
.card-list .card {
max-width: 36rem;
}
}
and 收紧闸门(两项都必须通过)。or 放宽闸门。not 为 不支持 的路径写样式——适合刻意的回退,但回退本身要完整、可读。
用 selector() 测试选择器
有些能力是选择器,不是属性。把它们包进 selector(),查询问的就是:“你能解析这个选择器吗?”
.nav a {
color: #0f172a;
text-decoration: none;
}
@supports selector(:has(*)) {
.nav:has(a:focus-visible) {
outline: 2px solid #2563eb;
outline-offset: 4px;
}
.card:has(img) .title {
font-weight: 700;
}
}
没有 selector() 时,在 @supports 里直接写裸的 :has() 并不可靠。有了它,缺少 :has() 的浏览器会跳过增强规则,只保留基线链接样式。
谁在问哪一类问题?
📊 Media, container, and feature queries
| 你在问什么 | 更适合何时 | 常用工具 |
|---|---|---|
| 视口 / 设备上下文有多宽? | 页面外壳、断点 | @media (…) |
| 包裹组件的 这个父级 有多宽? | 槽位宽度不等的卡片 | 设置 container-type 后用 @container (…) |
| 浏览器 是否支持这段 CSS? | 渐进增强 | @supports (…) / selector(…) |
三者可以干净地叠用:媒体管整页,容器管槽位,@supports 管能力。不要用 @supports 假冒断点,也不要用 @media 假冒特性检测。
先基线,再增强
实用写法是:把 共享 外观放在闸门外,把升级后的布局放进闸门里:
.feature-panel {
padding: 1.25rem;
border-radius: 0.75rem;
background: #f8fafc;
color: #0f172a;
}
.feature-panel .lead {
margin: 0 0 0.75rem;
font-size: 1.125rem;
line-height: 1.5;
}
.feature-panel .actions {
display: block;
}
.feature-panel .actions a {
display: inline-block;
margin: 0.25rem 0.5rem 0.25rem 0;
padding: 0.5rem 0.875rem;
border-radius: 0.5rem;
background: #e2e8f0;
color: inherit;
text-decoration: none;
}
@supports (display: flex) and (gap: 0.5rem) {
.feature-panel .actions {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.feature-panel .actions a {
margin: 0;
}
}
每个浏览器都能拿到内边距、排版和可点链接。Flex 与 gap 只在两者都被理解时出现——缺其一也不会留下空洞。
Nesting 与 @supports 并用
Modern Toolkit 的零件可以组合。Nesting 整理选择器;能力闸门仍由 @supports 负责:
.pricing {
padding: 1rem;
border: 1px solid #e2e8f0;
}
@supports (display: grid) {
.pricing {
display: grid;
gap: 1rem;
& .tier {
padding: 1rem;
background: #fff;
}
& .tier .price {
font-size: 1.5rem;
font-weight: 700;
}
}
}
若嵌套本身不受支持,在外侧保留扁平等价写法,或把嵌套形式当作增强路径的一部分——仍是同一套渐进增强思路。
自己动手试
- 先把列表做成简单纵向堆叠,再把 Grid 布局包进
@supports (display: grid)。 - 用
and同时要求gap,避免 flex/grid 间距半生效。 - 写
@supports not (display: grid)并配上明确的max-width回退——两条路径都应看起来是刻意设计的。 - 用
@supports selector(:has(*))闸住一条:has()规则。 - 别把 全部 视觉样式塞进
@supports;品牌色和排版留在基线里。
常见错误
- 把 唯一 可用布局全放进
@supports、没有基线——不支持的浏览器会看到残页 - 写
@supports (display)却不给值——特性查询需要属性–值对(或selector(…)) - 该用
@media的地方用了@supports(或反过来)——能力 ≠ 视口宽度 - 去测基线已经依赖的属性——只闸住 增强
- 为了小收益叠很深的
@supports——宁可一层清晰的增强
小结
@supports按 浏览器能力 闸住 CSS(特性查询)- 用
(property: value)测试,用and/or/not组合,选择器用selector() - 先有扎实基线;有支持再增强
- 记住三件套:
@media→ 视口,@container→ 父级尺寸,@supports→ 能力 - Modern Toolkit 到此结束——下一模块:无访问性与收尾(
accessibility)
🧠 测试您的知识
测试您的知识
通过这个互动测验挑战自己,看看你对这个主题的理解程度如何
📝 说明
- 仔细阅读每个问题
- 为每个问题选择最佳答案
- 您可以随时重新参加测验
- 您的进度将显示在顶部