CSS2025-01-02
返回首页

CSS Container Queries 实战:真正解决组件级响应式

CSS Container Queries 实战:真正解决组件级响应式

做了好几年前端,媒体查询(Media Query)一直有个让人不爽的地方:它只能根据视口宽度来调整样式。但实际开发中,一个组件可能在大屏的侧边栏里宽度只有 300px,在小屏下全宽反而有 375px。视口宽度一样,组件的实际空间完全不同。

Container Queries 解决的就是这个问题。它在 2023 年底拿到了所有主流浏览器的支持,到 2025 年已经成为我日常开发中用得最多的 CSS 特性之一。

基本用法

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

/* 根据容器的宽度调整样式 */
@container card (min-width: 400px) {
  .card {
    display: flex;
    gap: 1rem;
  }

  .card-image {
    width: 200px;
    flex-shrink: 0;
  }
}

@container card (max-width: 399px) {
  .card {
    display: block;
  }

  .card-image {
    width: 100%;
    margin-bottom: 1rem;
  }
}

container-type: inline-size 表示容器的宽度可以作为查询条件。container-name 是可选的,用来区分不同的容器。

实际项目中的场景

1. 卡片组件

这是我用得最多的场景。同一个卡片组件,放在首页全宽展示和放在侧边栏窄空间里,布局自动切换:

<!-- 首页:卡片容器很宽,水平布局 -->
<div class="card-wrapper" style="max-width: 800px">
  <div class="card">...</div>
</div>

<!-- 侧边栏:卡片容器很窄,垂直布局 -->
<div class="card-wrapper" style="max-width: 280px">
  <div class="card">...</div>
</div>

不用传 props 控制布局模式,CSS 自己就能搞定。组件的使用者不需要关心布局逻辑。

2. 导航栏

顶部导航在桌面端是水平菜单,在移动端抽屉里是垂直菜单。这两个场景其实都是同一个导航组件,只是容器宽度不同:

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

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

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

3. 表格组件

大容器里表格展示所有列,小容器里隐藏次要列:

.table-container {
  container-type: inline-size;
}

@container (max-width: 500px) {
  .table .col-secondary {
    display: none;
  }
}

container-type 的三种值

.wrapper {
  /* 只跟踪宽度 */
  container-type: inline-size;

  /* 只跟踪高度 */
  container-type: size;

  /* 宽高都跟踪 */
  container-type: size;
}

inline-size 的性能比 size 好很多,因为它只需要监控一个方向。大部分情况下 inline-size 就够了,size 只在极少数需要根据高度做调整的场景下使用。

container query units

这个是比较新的功能,允许用容器尺寸作为单位:

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

.card {
  /* cqw = container query width,1cqw = 容器宽度的 1% */
  font-size: clamp(14px, 2cqw, 20px);
  padding: 2cqw;
}

这样字体大小和间距会随着容器大小自动缩放。以前要实现这种效果只能用 vw 单位配合 calc 算,现在直接用 cqw 就行。

和 Tailwind CSS 配合

Tailwind CSS v3.2+ 支持 Container Queries。用 @tailwindcss/container-queries 插件:

<div class="@container">
  <div class="@md:flex @md:gap-4">
    <div class="@md:w-48">...</div>
    <div>...</div>
  </div>
</div>

语法和普通的响应式前缀类似,前面加个 @ 就行。

性能注意事项

Container Queries 的性能开销比 Media Query 大一些,因为浏览器需要实时监控容器尺寸的变化。不过在实际使用中,我还没遇到过性能问题。有两个建议:

  • 尽量用 inline-size 而不是 size
  • 避免在动画元素上使用 container query(会触发频繁重排)

浏览器兼容性

到 2025 年,所有主流浏览器都支持了。Safari 从 16.0 开始支持,Chrome 从 105 开始,Firefox 从 110 开始。基本上不需要考虑兼容性问题了。

写在最后

Container Queries 是 CSS 近年来最实用的特性之一。它让组件的样式可以真正与自身所处空间关联,而不是被迫依赖视口宽度。项目里大量用上之后,组件的复用性明显提高了,因为不用再通过 props 传各种布局模式了。

CSSTailwindCSS
返回首页