Skip to content

第十六章:CSS 容器查询(Container Queries)——响应式设计的革命性进化

传统的响应式设计依赖于视口尺寸@media 查询),但当组件需要根据自身容器而非整个屏幕调整样式时,@media 就显得力不从心。

CSS 容器查询(Container Queries) 正是为解决这一痛点而生——它让组件真正实现了“内聚响应式”,是现代组件化开发的里程碑。

本章将带你掌握容器查询的核心语法,并通过实战案例构建一个智能响应式卡片布局。


1. 容器查询的引入背景:为什么需要它?

传统 @media 的局限
css
/* 问题:卡片样式取决于屏幕宽度,而非容器 */
@media (max-width: 600px) {
  .card {
    font-size: 14px;
    padding: 12px;
  }
}
  • 上下文丢失:卡片在小容器中仍可能过大
  • 组件不独立:同一组件在不同布局中表现不一致
  • 维护困难:需为每个使用场景编写特定媒体查询
容器查询的突破

“组件知道自己的空间有多大”
卡片不再关心屏幕多宽,只关心父容器给它多少空间


2. 如何根据父容器的尺寸调整样式?

关键步骤:

  1. 将元素设置为“查询容器”
  2. 使用 @container 查询其尺寸
  3. 动态调整内部元素样式

3. 基本用法:@container 规则

① 定义查询容器
css
/* 指定该元素为“行内大小”(宽度)查询容器 */
.card-container {
  container-type: inline-size;
  container-name: card;
}
/* 简写 */
.card-container {
  container: card / inline-size;
}
  • container-type:
    • inline-size: 行内尺寸(通常为宽度)
    • block-size: 块级尺寸(通常为高度)
    • size: 同时查询宽高
② 使用 @container 查询
css
@container card (min-width: 300px) {
  .card-content {
    display: flex;
  }
  .card-image {
    width: 100px;
  }
}

@container card (max-width: 299px) {
  .card-content {
    flex-direction: column;
  }
  .card-image {
    width: 100%;
    margin-bottom: 8px;
  }
}
③ 支持的查询条件
查询说明
(min-width: 300px)容器宽度 ≥ 300px
(max-height: 200px)容器高度 ≤ 200px
(aspect-ratio: 1 / 1)容器宽高比
(style(--theme: light))查询自定义样式属性(实验性)

4. 浏览器支持与 Polyfill 方案

浏览器支持情况版本
Chrome✅ 支持105+
Edge✅ 支持105+
Firefox✅ 支持110+
Safari✅ 支持16.4+
iOS Safari✅ 支持16.4+

⚠️ 旧版浏览器降级方案

Polyfill 推荐:@container-query/polyfill
bash
npm install @container-query/polyfill
js
// main.js
import { applyContainerQueries } from '@container-query/polyfill';

applyContainerQueries();
优雅降级(Graceful Degradation)
css
/* 默认窄版样式 */
.card-content {
  display: block;
}

/* 仅在支持容器查询时覆盖 */
@supports (container-type: inline-size) {
  @container card (min-width: 300px) {
    .card-content {
      display: flex;
    }
  }
}

5. 实战案例:构建一个响应式卡片布局

需求
  • 卡片在窄容器中:垂直堆叠(图片在上)
  • 卡片在宽容器中:水平排列(图片在左)
  • 支持网格布局中的不同列宽
HTML 结构
html
<div class="grid">
  <div class="card-container">
    <div class="card">
      <img src="image.jpg" alt="Product" class="card-image">
      <div class="card-content">
        <h3 class="card-title">Product Name</h3>
        <p class="card-desc">Short description here.</p>
      </div>
    </div>
  </div>

  <!-- 更多卡片... -->
</div>
CSS 样式
css
.grid {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}

/* 设置查询容器 */
.card-container {
  container: card / inline-size;
}

.card {
  border: 1px solid #ddd;
  border-radius: 12px;
  overflow: hidden;
  background: white;
}

.card-image {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.card-content {
  padding: 16px;
  line-height: 1.5;
}

/* 宽容器:水平布局 */
@container card (min-width: 300px) {
  .card {
    display: flex;
  }
  .card-image {
    width: 120px;
    flex-shrink: 0;
    border-radius: 0;
  }
  .card-content {
    padding: 16px 16px 16px 0;
  }
}

/* 窄容器:垂直布局 */
@container card (max-width: 299px) {
  .card {
    display: block;
  }
  .card-image {
    width: 100%;
  }
  .card-content {
    padding: 16px;
  }
}
效果
  • 在 2列网格中(每列 ~300px+):卡片水平显示
  • 在 3列或更窄网格中:卡片垂直堆叠
  • 无需 JavaScript,纯 CSS 实现智能响应

结语:组件化时代的响应式新范式

容器查询标志着响应式设计从“页面驱动”迈向“组件驱动”。

它让组件真正实现了:

  • 上下文感知:知道自己的可用空间
  • 内聚响应:样式逻辑封装在组件内部
  • 可复用性:同一组件在任何布局中都能正确显示

适用场景

  • 组件库(Card、List、Sidebar)
  • 网格布局(Dashboard、Gallery)
  • 可嵌入小部件(Widget、Ad)

容器查询不是 @media 的替代品,而是它的补充
未来,我们将用 @media 控制页面结构,用 @container 控制组件内部

下一章,我们将进入“视口单位与动态排版”。