配了八年响应式,每次都要问「屏幕多宽」——今天 CSS 自己会问「容器多大」了,@container 把这件事彻底原生化了

配了八年响应式,每次写布局都要先问「屏幕多宽」——媒体查询帮你回答了屏幕有多宽,但它永远回答不了这个组件自己有多少空间。把同一个卡片塞进 1200px 主内容区是横排,塞进 280px 侧边栏就崩了——媒体查询束手无策,只能靠 JS 硬撑或者写一堆 .card--small 变体。今天 @container 把这件事彻底变了:CSS 终于可以问「我的容器给了我多少空间」,然后自己决定怎么排版。

媒体查询解决不了的问题

传统媒体查询是屏幕级的。@media (min-width: 768px) 问的是「浏览器窗口」有多宽,不是「这个卡片所在的格子」有多宽。

同一个卡片组件,会出现在:

  • 全宽 Hero 区 → 横排
  • 三栏产品网格 → 横排
  • 两栏对比区 → 横排
  • 280px 侧边栏 → 必须竖排

但视口可能是 1440px。媒体查询在所有场景下都返回「宽屏」,于是侧边栏里的卡片就崩了。

以前的解法:ResizeObserver + JS 动态切换 class,或者写一堆 variantprops。管用,但 CSS 不该靠 JS 看着。

@container 的解法:问容器,不问屏幕

第一步,给父级加 container-type

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

第二步,用 @container 写条件:

.card { display: flex; flex-direction: column; }

@container card (min-width: 400px) {
  .card {
    flex-direction: row; /* 容器 ≥ 400px,自动切横排 */
  }
}

同一个 HTML,同一个 CSS,卡片放进 1200px 主内容区是横排,放进 280px 侧边栏自动变竖排——JS 零行,媒体查询管不着的它管了。

三类容器查询,2026 年全部就绪

尺寸查询(最常用):

@container (width > 480px) { ... }
@container card (min-width: 600px) { ... }

支持范围语法 ><= 和逻辑组合 and / or / not

Style 查询(2026 年稳定,所有主流引擎支持):

.card-wrapper { --theme: dark; }

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

Query 的是 CSS 变量,不是 computed style——目前只能查 custom properties,但这个能力已经让纯 CSS 主题切换成为可能。

Scroll-State 查询(最新,2026 年正式进 Baseline):

@container scroll-state(scrolled-y) {
  .header { box-shadow: 0 2px 8px rgba(0,0,0,0.2); }
}

纯 CSS 响应滚动状态,不需要 onscroll 监听器。

容器单位:cqi / cqw,流动排版专用

和 vw/vh 类似,但基准是容器不是视口:

.card-title {
  font-size: clamp(1rem, 5cqi, 2.5rem); /* 随容器宽度缩放 */
}
.card-body {
  padding: 4cqw 6cqw; /* 内边距也随容器走 */
}

cqi 是 inline 轴的 1%,支持书写模式(竖排文字场景下 inline 轴是垂直的);cqw 永远是物理宽度。实战中 cqi 用得更多。

性能:比 ResizeObserver 快 35%

codercops.com 的实测:把 47 个组件的设计系统从媒体查询迁移到容器查询,删掉了 23 个 variantprops 和对应的 JS 逻辑。一家 SaaS 团队在大型仪表盘里用了几十个容器,中档笔记本每次布局重算开销约 10–15ms——在现代浏览器(Chromium/Gecko/WebKit 均已优化 containment 逻辑)里,这个成本完全可以接受。

实战建议:

  • 只给真正需要响应容器大小的组件加 container-type,不要给每个 div 都加
  • 优先用 inline-size(只管宽度),不用 size(宽高都管)——后者有额外的布局约束开销
  • 避免在动画过程中改变容器宽高(触发 query 重新计算)

媒体查询和容器查询怎么分工

不是二选一,是分工:

场景 用什么
全页栅格:1栏→3栏 @media
导航栏在移动端收起 @media
卡片从竖排变横排 @container
侧边栏小部件自适应 @container
系统暗色模式 @media (prefers-color-scheme: dark)
组件根据 CSS 变量切换主题 @container style()

下一步:5 分钟迁移一个卡片组件

  1. 给卡片外层加 container-type: inline-size;
  2. 把原来针对该卡片的媒体查询换成 @container(宽度阈值按卡片实际需求设,不要照抄全站断点)
  3. 删掉对应的 JS ResizeObserver 逻辑

迁移完之后,这个卡片在任何布局上下文里都能自己适应——放进 Modal、侧边栏、主内容区,都不需要改一行 HTML 或加一个 class。


来源:MDN CSS Container Queries 官方文档 + codercops.com 2026 State of CSS(2400行删除案例)+ thelinuxcode.com 性能实测 + dev.to 三类容器查询实战 + layoutscene.com 2026 完整指南

评论区

0 条评论

登录后可评论。