CSS容器查询实战:让组件自适应容器而不是视口
我们可能已经习惯了用媒体查询来适配视口宽度,但当同一个组件被塞进侧边栏、主内容区甚至弹窗里时,视口尺寸并不能决定一切。CSS容器查询带来的核心思路是:让组件根据“自己所在的容器”来调整布局。组件终于不是仰望视口,而是低头看自己的地盘了。
从媒体查询到容器查询
媒体查询问的是“屏幕现在多宽?”,而容器查询问的是“我的容器现在多宽?”。这在组件化开发中非常实用。同样一个商品卡片,在首页宽大的内容区里可以左图右文,在侧边栏那 240px 的窄空间里却只适合上下堆叠。过去我们要用媒体查询把断点绑定到全局视口,导致组件在不同页面复用时反复打补丁。容器查询允许我们把断点下沉到组件边界,真正实现“组件自治”。
基础用法
要让某个祖先元素成为可查询的容器,需要给它声明一下:
.card-container {
container-type: inline-size;
container-name: product;
}
`container-type: inline-size` 表示只关注容器的宽度方向,避免生成不必要的布局约束。然后就能用 `@container` 了:
@container product (min-width: 400px) {
.card .info {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
这里的 `min-width` 不再是视口宽度,而是 `.card-container` 的实际内容宽度。建议在复杂项目里给容器起个明确名字,否则它会查询最近一层未命名的容器,稍不留神就容易作用到错误节点上。
实战例子
假设我们有一套文章卡片组件,它既会出现在宽达 600px 的主内容区,也会出现在只有 240px 的侧边栏里。先给它的父层定义容器:
.widget {
container: article-card / inline-size;
}
卡片结构大约是图片、标题、摘要。默认情况下,图片在上、摘要在下,适合窄场景:
.article-card__body {
display: flex;
flex-direction: column;
}
.article-card__summary {
display: none;
}
当容器宽度达到 300px 时,宽场景足够容纳横排布局,于是切换成左右结构并显示出摘要:
@container article-card (min-width: 300px) {
.article-card__body {
flex-direction: row;
align-items: center;
}
.article-card__summary {
display: block;
}
}
注意,这里的断点与视口无关。哪怕视口只有 320px,只要该组件所在容器足够宽,它就仍然可以横排展示。这就是组件级响应式的底气。
容器查询还带来了对应的容器单位,例如 `cqw` 代表容器宽度的 1%,`cqh` 代表容器高度的 1%。我们可以让标题字号跟着容器走:
.card-title {
font-size: 3cqw;
}
这种动态行为在封装通用组件时堪称降维打击,比靠 JS 测量尺寸再改样式要干净得多。
一些坑和限制
容器查询会让被标记的元素创建新的包含块和层叠上下文,部分绝对定位的子元素位置可能会变,需要测试。若没有特殊需求,尽量用 `inline-size` 而不是 `size`,后者要求容器必须有确定的高度,否则容器自身会塌陷
管理员
黑卡会员