正在加载...

CSS 特性查询

容器查询问的是 父级 有多宽。媒体查询盯着 视口。特性查询问的是另一件事:这个 浏览器 懂这段 CSS 吗?用 @supports,你先交付可靠的基础样式,再只在引擎能处理的地方解锁现代布局或选择器。

渐进增强,不是赌博

特性查询是一道 能力闸门。你不会删掉旧样式——而是保留处处可用的布局,再在 @supports 里加上更丰富的一层,前提是引擎能解析你需要的特性(例如 display: grid,或 flex 上的 gap)。

基本的 @supports

常见写法测试一对 属性–值。浏览器能处理该声明时,块内规则才会生效:

Unlock Grid only when Grid is understood

css
.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

你可以同时要求多项特性、接受任一替代项,或把测试反过来:

and, or, and not in feature queries

css
@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(),查询问的就是:“你能解析这个选择器吗?”

Gate styles that need :has()

css
.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 假冒特性检测。

先基线,再增强

实用写法是:把 共享 外观放在闸门外,把升级后的布局放进闸门里:

Shared skin outside; enhanced layout inside

css
.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 负责:

Nesting inside a support block

css
.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;
}
}
}

若嵌套本身不受支持,在外侧保留扁平等价写法,或把嵌套形式当作增强路径的一部分——仍是同一套渐进增强思路。

自己动手试

  1. 先把列表做成简单纵向堆叠,再把 Grid 布局包进 @supports (display: grid)。
  2. 用 and 同时要求 gap,避免 flex/grid 间距半生效。
  3. 写 @supports not (display: grid) 并配上明确的 max-width 回退——两条路径都应看起来是刻意设计的。
  4. 用 @supports selector(:has(*)) 闸住一条 :has() 规则。
  5. 别把 全部 视觉样式塞进 @supports;品牌色和排版留在基线里。

常见错误

  • 把 唯一 可用布局全放进 @supports、没有基线——不支持的浏览器会看到残页
  • 写 @supports (display) 却不给值——特性查询需要属性–值对(或 selector(…))
  • 该用 @media 的地方用了 @supports(或反过来)——能力 ≠ 视口宽度
  • 去测基线已经依赖的属性——只闸住 增强
  • 为了小收益叠很深的 @supports——宁可一层清晰的增强

小结

  • @supports 按 浏览器能力 闸住 CSS(特性查询)
  • 用 (property: value) 测试,用 and / or / not 组合,选择器用 selector()
  • 先有扎实基线;有支持再增强
  • 记住三件套:@media → 视口,@container → 父级尺寸,@supports → 能力
  • Modern Toolkit 到此结束——下一模块:无访问性与收尾(accessibility)

🧠 测试您的知识

准备开始

测试您的知识

通过这个互动测验挑战自己,看看你对这个主题的理解程度如何

❓
6
问题
🎯
70%
及格要求
♾️
∞
时间
🔄
∞
尝试次数

📝 说明

  • 仔细阅读每个问题
  • 为每个问题选择最佳答案
  • 您可以随时重新参加测验
  • 您的进度将显示在顶部