媒体查询回答“屏幕多宽”,容器查询回答“我这块地方多大”。对组件库来说,后者才是它真正的痛点:一张卡片被放进全宽列表、双列网格、三列网格、窄侧栏时,它的理想内部布局各不相同,但屏幕宽度却可能完全一样。
最小语法
/* 声明容器 */
.card-slot {
container-type: inline-size;
container-name: card;
}
/* 子元素按容器宽度切换 */
@container card (min-width: 40rem) {
.card {
display: grid;
grid-template-columns: 8rem 1fr;
}
}
container-type: inline-size 让容器按行内尺寸(逻辑上的“宽度”)提供查询基准;子树内任何元素都能 @container 查询它,不必是直接子级。
一个真实的复用场景
文章推荐卡需要出现在三种环境:全宽(单列+横排大缩略区)、双列网格(竖排)、侧栏(竖排紧凑)。纯媒体查询方案要为每种页面断点写一遍覆盖,而容器查询只需卡片自己声明:
.slot {
container-type: inline-size;
}
@container (min-width: 30rem) {
.post-card {
grid-template-columns: 1fr;
} /* 够宽:标题描述并排余裕 */
.post-card__excerpt {
-webkit-line-clamp: 3;
} /* 多展示一行 */
}
@container (max-width: 20rem) {
.post-card__meta {
flex-direction: column;
} /* 很窄:meta 换行堆叠 */
}
卡片被放进哪个容器,就按那个容器说话。新增页面布局时零成本——这正是组件级响应式的复利。
边界与坑
container-type会让容器成为包含块,内部position: absolute的定位基准随之改变;含浮出元素(tooltip、下拉)的容器要先验证。- 只能按行内尺寸和样式查询(
inline-size/size/style()),容器查询不能基于内容高度触发——那仍是 JS/IntersectionObserver的领域(container-type: size会要求块方向尺寸也固定,实践中很少用)。 - 回退:不支持的浏览器直接忽略
@container块,样式安全退化到基线布局。给基线一套“哪个宽度都不算错”的默认样式即可,无需 JS 检测。 - 不要滥用:视口级的全局布局(页眉、主栏)仍该用媒体查询;容器查询解决的是“同一组件多环境”,两者不是替代关系。
与工具类的组合
Tailwind v4 已内置容器查询变体(@container、@md/container: 一类),工程上更常见的落地是:给插槽类加 @container,组件用变体写差异,避免手维护容器名。
小结
容器查询的真正价值不是新语法,而是关注点归位:布局决策从“页面知道组件在哪”退回到“组件知道自己多大”。一张卡片学会看容器下菜碟之后,你在十个新场景里复用它都不需要再写第十套断点。