返回博客

Wordpress建站

CSS 容器查询完全指南:从基础语法到实战应用

2026-07-18

阅读约:26分钟

长期以来,前端开发者依赖 媒体查询(Media Queries)实现响应式布局,但媒体查询基于视口(viewport)尺寸做判断,无法感知组件自身的容器大小。当同一个组件被放置在不同宽度的侧边栏、主内容区或弹窗中时,仅靠媒体查询难以让组件自适应其父容器。

CSS 容器查询(CSS Container Queries)正是为了解决这一问题而诞生的。它允许组件根据自身所在容器的尺寸变化来调整样式,真正实现"组件级响应式设计"。

什么是容器查询

容器查询是一种基于 祖先容器 的尺寸(或样式特征)来应用不同样式的 CSS 条件规则。其核心思想是:

组件不关心整个页面的宽度,只关心自己被放在了多大的空间里。

浏览器支持情况:Chrome 105+、Safari 16+、Firefox 110+ 已全面支持,主流浏览器覆盖率已超过 90%。

基础语法

1. 声明容器

要让一个元素成为"容器",需要使用 container-typecontainer-name 属性:

.card-wrapper {
  container-type: inline-size;
  container-name: card-container;
}

也可以使用简写形式 container:

.card-wrapper {
  container: card-container / inline-size;
}

2. container-type 的取值

说明
inline-size对容器的行内轴(宽度)建立查询
size对容器的宽度和高度都建立查询
normal默认值,不建立查询

实际开发中,inline-size 是最常用的值,因为宽度通常是布局的主要变量。使用 size 需要格外小心,如果容器的高度由内容决定,容易导致死循环。

3. 编写容器查询

使用 @container 规则根据容器尺寸应用样式:

@container card-container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 200px 1fr;
  }

  .card-title {
    font-size: 1.5rem;
  }
}

4. 省略容器名称

如果不指定 container-name@container 会沿 DOM 树向上查找最近的容器祖先:

.card-wrapper {
  container-type: inline-size;
}

/* 自动匹配最近的容器 */
@container (min-width: 400px) {
  .card-content {
    flex-direction: row;
  }
}

容器查询单位

容器查询引入了一组新的 CSS 单位,类似于视口单位(vwvh),但基于容器的尺寸:

单位说明
cqw容器宽度的 1%
cqh容器高度的 1%
cqi容器行内尺寸的 1%
cqb容器块尺寸的 1%
cqmincqi 和 cqb 中较小值的 1%
cqmaxcqi 和 cqb 中较大值的 1%
@container (min-width: 400px) {
  .card-image {
    width: 30cqw; /* 容器宽度的 30% */
    height: 20cqh; /* 容器高度的 20% */
    font-size: 3cqi; /* 字体随容器缩放 */
  }
}

容器查询 vs 媒体查询

对比维度媒体查询 @media容器查询 @container
查询依据视口尺寸祖先容器尺寸
作用范围全局页面级组件级
可复用性组件在不同位置可能表现不一致组件在任何容器中都自适应
设计理念页面驱动组件驱动
适用场景整体布局切换(如移动端/桌面端)可复用组件的内部响应式

关键结论:容器查询不会取代媒体查询,二者是互补关系。页面级布局仍适合媒体查询,组件内部自适应则用容器查询。

实战案例

案例 1:自适应卡片组件

<div class="card-wrapper">
  <div class="card">
    <img class="card-image" src="photo.jpg" alt="封面">
    <div class="card-body">
      <h3 class="card-title">文章标题</h3>
      <p class="card-desc">文章摘要内容,在宽容器中展示更多文字...</p>
      <button class="card-btn">阅读更多</button>
    </div>
  </div>
</div>
.card-wrapper {
  container-type: inline-size;
  container-name: card;
}

.card {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1rem;
  border-radius: 12px;
  background: #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.card-image {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 8px;
}

.card-desc {
  display: none; /* 窄容器下隐藏摘要 */
}

/* 容器宽度 >= 400px 时切换为横向布局 */
@container card (min-width: 400px) {
  .card {
    flex-direction: row;
    align-items: center;
  }

  .card-image {
    width: 200px;
    aspect-ratio: auto;
    height: 150px;
    flex-shrink: 0;
  }

  .card-desc {
    display: block; /* 显示摘要 */
    color: #666;
    font-size: 0.9rem;
    line-height: 1.6;
  }
}

/* 容器宽度 >= 600px 时进一步放大 */
@container card (min-width: 600px) {
  .card {
    padding: 1.5rem;
  }

  .card-image {
    width: 280px;
    height: 200px;
  }

  .card-title {
    font-size: 1.5rem;
  }
}

同一个 .card-wrapper 放在 300px 的侧边栏和 700px 的主内容区中,会自动呈现不同的布局,无需任何 JavaScript 干预。

案例 2:响应式导航栏

.nav-wrapper {
  container-type: inline-size;
  container-name: nav;
}

.nav {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.nav-links {
  display: none;
}

.nav-toggle {
  display: block;
}

@container nav (min-width: 500px) {
  .nav-links {
    display: flex;
    gap: 1.5rem;
  }

  .nav-toggle {
    display: none;
  }
}

@container nav (min-width: 800px) {
  .nav-links {
    gap: 2rem;
    font-size: 1.1rem;
  }
}

这个导航栏组件可以放在页面顶部(宽容器),也可以嵌入侧边面板(窄容器),自动切换展示模式。

容器查询的样式查询

容器查询的样式查询

除了尺寸查询,CSS 还支持 样式查询(Style Queries),允许根据容器上设置的 CSS 自定义属性值来应用样式:

.card-wrapper {
  container-type: inline-size;
  container-name: card;
}

/* 通过自定义属性控制主题变体 */
.card-wrapper[data-theme="dark"] {
  --card-theme: dark;
}

@container card style(--card-theme: dark) {
  .card {
    background: #1a1a2e;
    color: #e0e0e0;
  }
}

样式查询目前的支持度还在推进中,建议在生产环境中结合尺寸查询谨慎使用。

最佳实践

1. 容器粒度选择

container-type 声明在 组件的直接父包裹元素 上,而不是过高的祖先节点。容器层级越精确,查询越可控。

/* 推荐:精确控制 */
.sidebar .card-wrapper { container-type: inline-size; }

/* 不推荐:容器层级过高,影响范围不可预测 */
.page-content { container-type: inline-size; }

2. 合理命名容器

使用有语义的 container-name 避免冲突:

/* 推荐 */
container-name: product-card;
container-name: nav-bar;

/* 不推荐 */
container-name: c1;
container-name: wrapper;

3. 渐进增强策略

为不支持容器查询的浏览器提供降级方案:

/* 默认样式(降级方案) */
.card {
  display: flex;
  flex-direction: column;
}

/* 容器查询(渐进增强) */
@supports (container-type: inline-size) {
  .card-wrapper {
    container-type: inline-size;
  }

  @container (min-width: 400px) {
    .card {
      flex-direction: row;
    }
  }
}

也可以结合媒体查询作为后备:

/* 媒体查询作为后备 */
@media (min-width: 768px) {
  .card {
    flex-direction: row;
  }
}

/* 容器查询优先(浏览器支持时覆盖) */
@container (min-width: 400px) {
  .card {
    flex-direction: row;
  }
}

4. 避免过度嵌套

容器查询支持多层嵌套,但嵌套过深会增加维护成本。建议控制在 2-3 层以内。

5. 性能考量

容器查询的匹配在布局阶段完成,浏览器对其做了优化。但需注意:

  • 避免在大量同级元素上同时声明容器
  • container-type: size inline-size 开销更大
  • 结合 will-change 提示浏览器优化频繁变化的容器

与现代 CSS 的协作

容器查询可以与以下 CSS 特性无缝配合:

  • CSS Grid / Flexbox:在容器查询内切换布局模式
  • CSS Nesting:在嵌套语法中直接使用 @container
  • :has() 选择器:结合父元素状态实现更精确的查询
  • @layer:在 Cascade Layer 中组织容器查询的优先级
@layer components {
  .card-wrapper {
    container-type: inline-size;
    container-name: card;
  }

  @container card (min-width: 400px) {
    .card { flex-direction: row; }
  }
}

常见问题

Q1:容器查询会取代媒体查询吗?

不会。媒体查询适合页面级别的响应式(如整体布局从单列切换到多列),容器查询适合组件级别。两者互补使用效果最佳。

Q2:为什么 size 类型不常用?

size 同时监听宽高变化,如果容器高度由内容决定(height: auto),内容变化会影响容器高度,容器高度变化又触发查询,可能导致循环。inline-size 只监听宽度,更加安全。

Q3:容器查询能查询样式吗?

可以。通过 @container style() 语法可以查询容器上的 CSS 自定义属性,但样式查询的浏览器支持度目前不如尺寸查询广泛。

Q4:如何调试容器查询?

在 Chrome DevTools 中,可以检查元素时看到容器查询的匹配状态。此外,CSS.containerQuery API 允许 JavaScript 监听容器尺寸变化。

总结

CSS 容器查询是响应式设计领域最重要的演进之一。它将响应式的关注点从视口级别下沉到组件级别,让可复用组件真正做到"放到哪里都好看"。

核心要点回顾:

  • container-type: inline-size 声明容器
  • @container 编写条件样式
  • cqw / cqh 等容器单位实现弹性尺寸
  • 结合媒体查询做渐进增强
  • 合理命名、控制嵌套层级、注意性能

随着浏览器支持的完善,容器查询已经成为现代前端项目中不可或缺的工具。如果你正在构建组件库或设计系统,现在是引入容器查询的最佳时机。

标签:

响应式设计 容器查询 现代CSS