为什么我们需要 Container Queries?

多年来,开发者一直依赖 CSS Media Queries 来实现响应式布局。但 Media Queries 有一个根本性的局限:它们只能基于视口(viewport)的尺寸来做判断。这意味着即使一个组件被放在一个很窄的侧边栏里,它也不知道自己的可用空间有多小——因为它只关心整个屏幕有多大。

这正是 Container Queries(容器查询)要解决的问题。CSS Container Queries 是 CSS 近年来最激动人心的特性之一,它允许组件根据其父容器的尺寸而非视口来调整自身的样式,真正实现了组件级别的响应式设计。

/* 传统方式:基于视口 */
@media (max-width: 768px) {
  .card { flex-direction: column; }
}

/* 容器查询:基于父容器 */
.card-container {
  container-type: inline-size;
  container-name: card;
}

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

核心概念与语法

1. 声明容器

要让一个元素成为查询容器,你需要使用 container-type 属性。它有两个主要值:

  • inline-size:基于内联方向(通常是宽度)建立查询,最常用
  • size:基于内联和块方向(宽度和高度)建立查询,但会同时启用两个轴的containment,性能开销更大
.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

/* 简写形式 */
.sidebar {
  container: sidebar / inline-size;
}

2. 编写容器查询规则

使用 @container 规则,语法与 @media 类似:

/* 基于容器名称的查询 */
@container sidebar (min-width: 400px) {
  .widget {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

/* 不包含容器名称的查询(匹配所有容器) */
@container (max-width: 300px) {
  .card {
    padding: 0.5rem;
  }
}

/* 范围语法(现代浏览器支持) */
@container (400px <= width <= 800px) {
  .card { font-size: 1rem; }
}

实战案例:自适应卡片组件

假设我们需要一个卡片组件,在不同容器宽度下呈现不同的布局:

<!-- 在任何地方都可以复用,自适应容器 -->
<div class="card-container">
  <article class="card">
    <div class="card__image">
      <img src="photo.jpg" alt="封面" loading="lazy" />
    </div>
    <div class="card__body">
      <h3 class="card__title">文章标题</h3>
      <p class="card__desc">这是一段描述文字...</p>
      <div class="card__meta">
        <span>2024-01-15</span>
        <span>· 5分钟阅读</span>
      </div>
    </div>
  </article>
</div>
/* 声明容器 */
.card-container {
  container-type: inline-size;
  container-name: card;
}

/* 默认布局:紧凑模式(容器宽度 < 400px) */
.card {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 0.75rem;
  border: 1px solid #e2e8f0;
  border-radius: 8px;
}

.card__image img {
  width: 100%;
  height: 180px;
  object-fit: cover;
  border-radius: 4px;
}

/* 中等宽度:水平布局(400px - 699px) */
@container card (min-width: 400px) {
  .card {
    flex-direction: row;
    align-items: center;
  }

  .card__image {
    flex: 0 0 160px;
  }

  .card__image img {
    height: 120px;
  }

  .card__body {
    flex: 1;
  }

  .card__title {
    font-size: 1.1rem;
  }
}

/* 宽容器:大图水平布局(>= 700px) */
@container card (min-width: 700px) {
  .card {
    flex-direction: row;
    align-items: stretch;
    gap: 1.25rem;
    padding: 1.25rem;
  }

  .card__image {
    flex: 0 0 320px;
  }

  .card__image img {
    height: 220px;
  }

  .card__title {
    font-size: 1.4rem;
    margin-bottom: 0.5rem;
  }

  .card__desc {
    font-size: 1rem;
    line-height: 1.6;
  }
}

案例二:CSS-only 响应式导航栏

不需要 JavaScript,仅用 CSS Container Queries 就能实现导航栏在窄容器中自动收起:

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

/* 宽容器:水平展开导航 */
.navbar {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.nav-links {
  display: flex;
  gap: 1.5rem;
  list-style: none;
  margin-left: auto;
}

/* 窄容器:折叠菜单 */
@container nav (max-width: 500px) {
  .navbar {
    flex-wrap: wrap;
  }

  .nav-links {
    display: none;
    width: 100%;
    flex-direction: column;
    padding: 1rem 0;
    gap: 0.75rem;
  }

  .nav-toggle {
    display: block;
    margin-left: auto;
  }

  .nav-toggle:checked ~ .nav-links {
    display: flex;
  }
}

Container Queries 与 Media Queries 对比

维度Media QueriesContainer Queries
查询基准视口(viewport)宽度/高度父容器(container)尺寸
复用性依赖页面结构,组件不可复用组件自适应,可在任意位置复用
代码语义描述「屏幕大小」描述「组件可用空间」
适用范围整体页面布局微观组件样式
浏览器支持✅ 100%+✅ Chrome 105+, Firefox 110+, Safari 16+

最佳实践:两者不是替代关系,而是互补。Media Queries 控制页面整体布局(如侧边栏宽度),Container Queries 控制组件内部样式(如网格列数、字号等)。

高级用法:容器查询单位

除了条件样式,Container Queries 还引入了新的长度单位,相对于容器尺寸计算:

  • cqw:容器宽度的 1%
  • cqh:容器高度的 1%
  • cqi:容器内联方向尺寸的 1%
  • cqb:容器块方向尺寸的 1%
  • cqmin:cqi 和 cqb 中较小的值
  • cqmax:cqi 和 cqb 中较大的值
.card-container {
  container-type: inline-size;
}

.card-title {
  /* 字号随容器宽度平滑变化 */
  font-size: clamp(1rem, 5cqw, 2rem);
}

.card-icon {
  /* 图标大小随容器同比缩放 */
  width: 10cqw;
  height: 10cqw;
}

这些单位特别适合图标、字体等需要随容器同比缩放的场景,避免了传统的媒体查询断点阶梯式跳变。

渐进增强方案

对于需要支持旧浏览器的项目,可以使用 @supports 做渐进增强:

/* 基础样式(所有浏览器) */
.card {
  display: flex;
  flex-direction: column;
}

/* 仅支持容器查询的浏览器生效 */
@supports (container-type: inline-size) {
  .card-container {
    container-type: inline-size;
    container-name: card;
  }

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

再加上 @container 规则本身的特性——不支持的浏览器会直接忽略整个规则块,这比使用 JavaScript polyfill 更稳健。唯一的 polyfill(如 Google 的 container-query-polyfill)适用于需要完美兼容 IE11 的场景,但现代项目一般建议渐进增强即可。

总结

CSS Container Queries 代表了 CSS 向组件化方向的重要演进。它让组件开发者可以编写"一次定义、处处适应"的样式,不必再依赖外部环境来判断自己该显示成什么样子。

在现代浏览器支持率已经超过 90% 的 2026 年,是时候在你的项目中拥抱 Container Queries 了。从最基础的卡片组件开始,逐步用它替代那些"虽然能用但总觉得不够优雅"的媒体查询 hack,你会发现组件的复用性和可维护性都有了质的飞跃。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部