CSS Container Queries 容器查询

FreeGuideOnline 最新 2026-07-11

CSS Container Queries 完全指南

长期以来,响应式设计主要依赖 Media Queries(媒体查询),根据视口(viewport)的宽度调整样式。但组件往往需要根据自身父容器的可用空间,而非整个视口来决定布局。Container Queries(容器查询) 解决了这一痛点,让你能够创建真正独立、可复用的响应式组件。

1. 什么是容器查询?

容器查询允许你基于一个容器元素的尺寸(宽度、高度、内联尺寸等),而非浏览器视口,来应用 CSS 样式。这意味着组件可以根据放置它的空间大小自适应,无论该空间是整个页面、一个侧边栏还是一个网格单元格。

核心概念对比:

  • 媒体查询@media (min-width: 768px) → 询问视口宽度是否 ≥768px
  • 容器查询@container (min-width: 400px) → 询问当前包含块(定义为容器的祖先)的宽度是否 ≥400px

2. 容器查询的基本语法

使用容器查询分为两步:定义容器编写查询规则

2.1 定义容器

默认情况下,任何元素都不是查询容器。你需要使用 container-type 属性显式声明一个元素为容器。也可以使用 container 简写同时设置类型和名称。

/* 将元素定义为内联尺寸容器(查询宽度) */
.container {
  container-type: inline-size;
}

/* 同时设置容器名称(便于多容器区分) */
.card-wrapper {
  container: card-container / inline-size;
}

container-type 可选值:

  • inline-size:创建一个查询元素内联尺寸(通常是宽度,取决于书写模式)的容器。适合大多数横向布局。
  • size:同时查询元素的内联和块级尺寸(宽度和高度)。某些布局可能需要高度查询。
  • normal:默认值,元素不是查询容器。

定义容器后,它便成为一个“包含上下文”(Containment Context),这可能会影响内部绝对定位元素的行为。

2.2 编写容器查询规则

使用 @container 规则,语法与媒体查询极其相似:

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

你可以添加容器名称来限定查询范围:

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

逻辑运算符同样支持:andornot。也支持范围语法 (width > 300px)

3. 容器查询长度单位

为配合容器查询,CSS 引入了与容器尺寸相对的单位:

  • cqw:容器宽度的 1%
  • cqh:容器高度的 1%
  • cqi:容器内联尺寸的 1%
  • cqb:容器块级尺寸的 1%
  • cqmincqicqb 中较小值的 1%
  • cqmaxcqicqb 中较大值的 1%

这些单位让字体、间距、边框半径等随容器缩放变得异常简单:

.card__title {
  font-size: 3cqi; /* 标题字体为容器内联尺寸的 3% */
  padding: 2cqi;
}

4. 第一个容器查询示例

下面创建一个简单的卡片组件,它会在容器宽度较小时纵向堆叠,容器变宽时横向排列。

HTML 结构:

<div class="card-container">
  <div class="card">
    <img src="image.jpg" alt="" class="card__image">
    <div class="card__content">
      <h2>标题</h2>
      <p>这是卡片的描述内容,会根据容器宽度重新布局。</p>
    </div>
  </div>
</div>

CSS 样式:

/* 定义容器 */
.card-container {
  container-type: inline-size;
}

/* 基础样式:纵向布局 */
.card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1rem;
  border: 1px solid #ccc;
}

/* 容器宽度大于 450px 时,变为横向 */
@container (min-width: 450px) {
  .card {
    flex-direction: row;
  }
  .card__image {
    width: 40%;
    object-fit: cover;
  }
  .card__content {
    flex: 1;
  }
}

.card-container 放入一个窄栏或宽栏,卡片会自动适应,无需依赖视口宽度。

5. 容器查询与媒体查询的协作

两者并非替代关系,而是互补:

  • 媒体查询:用于页面级布局,如栅格系统、导航栏形式改变。
  • 容器查询:用于组件级响应,如卡片内部重排、组件内元素的显隐。

一个典型的组合用法:页面使用 Media Query 调整网格列数,组件内部使用 Container Query 根据网格单元格实际大小微调细节。

6. 命名容器与多层嵌套

当页面包含多个不同容器时,通过容器名称精准控制。

.sidebar {
  container: sidebar-container / inline-size;
}
.main-content {
  container: main-container / inline-size;
}

/* 仅对 sidebar 容器内的元素应用 */
@container sidebar-container (max-width: 300px) {
  .nav-item {
    display: block;
  }
}

如果嵌套定义容器,内部的元素会查询最近的祖先容器,除非你指定了容器名称。未命名的查询(@container 不带名称)会匹配最近的非命名容器。

7. 使用容器查询长度单位实现动态排版

结合 cqi 单位,可以实现完全流畅的组件:

.card {
  container-type: inline-size;
  /* 其他样式 */
}

.card__title {
  font-size: clamp(1rem, 5cqi, 2.5rem);
}

这样标题大小会随着容器宽度平滑缩放,不会在任何断点处突变,始终保持可读性。

8. 条件查询:style() 查询(实验性)

容器查询规范还扩展了 样式查询(Style Queries),允许你根据容器自身的自定义属性值(CSS 变量)来决定子元素的样式。目前大多数浏览器已支持。

@container style(--theme: dark) {
  .child {
    color: #fff;
    background: #333;
  }
}

这为基于“主题”或“模式”的样式提供了原生 CSS 方案,无需额外类名。

9. 浏览器支持与渐进增强

容器查询的浏览器支持已相当完善:

  • container-type, container, @container, 容器单位:Chrome 105+, Edge 105+, Safari 16+, Firefox 110+。
  • 样式查询:Chrome 111+, Edge 111+, Safari 18+, Firefox 暂不支持(截至 2025 年初)。

渐进增强策略: 先书写不依赖容器查询的基础样式(保证老旧浏览器的可用性),然后在 @supports 中编写增强样式:

.card {
  display: block; /* 降级方案 */
}

@supports (container-type: inline-size) {
  .card-container {
    container-type: inline-size;
  }
  @container (min-width: 400px) {
    .card {
      display: flex;
    }
  }
}

10. 常见问题与最佳实践

  • 性能:定义容器会触发 CSS Containment,浏览器可以更高效地计算布局,通常不会带来性能负担,反而可能提升渲染性能。
  • 不要过度容器化:一个页面中存在过多容器查询可能增加维护复杂度,应优先为可复用的组件定义容器。
  • 高度查询:使用 container-type: size 并查询高度(@container (min-height: 200px))时,注意必须显式设置容器的高度,否则高度依赖内容,容易造成循环计算。通常情况谨慎使用。
  • 调试工具:Chrome DevTools 会标记容器元素,并在样式面板中显示匹配的 @container 规则,方便调试。

11. 总结

容器查询将响应式设计的控制权从视口转移到父容器,让组件真正实现“一次编写,处处运行”。它是构建现代设计系统、微前端和组件库的基石。掌握 container-type@container 和容器相对单位,你的页面组件将变得更加灵活和可维护。

下一步建议:尝试在现有项目中为一个小组件加入容器查询,感受它与传统媒体查询在设计思维上的差异。