CSS 容器查询
嵌套(Nesting) 把组件选择器收在一处。媒体查询 仍盯着 视口。容器查询 问的是另一个问题:这个父级盒子 有多宽?同一张商品卡可以在窄侧栏里保持紧凑,在主栏里展开——即使浏览器窗口宽度没变。
为什么光有视口不够
版式里常把 同一个组件 放进宽度不等的槽位:16rem 的侧栏轨道和弹性的主区域。两个槽位共享同一视口宽度,@media (min-width: …) 对两者触发方式相同。样式应取决于包裹卡片的 容器,而不是整屏。
建立尺寸 containment 上下文
选出需要上报尺寸的父元素。设置 container-type——通常用 inline-size,以便查询父级的行内尺寸(横排书写时即宽度),而不必在两条轴上都做完整尺寸 containment:
.rail {
container-type: inline-size;
container-name: rail;
width: 16rem;
padding: 1rem;
background: #f8fafc;
}
.stage {
container-type: inline-size;
container-name: stage;
flex: 1;
min-width: 0;
padding: 1.25rem;
}
没有 container-type,@container 就没有可靠的可测量对象。container-name 可选;多个祖先都是容器时,用名称精确指向其中一个。
用 @container 查询容器
准备好父级后,把规则包在带尺寸条件的 @container 里。后代在 该 盒子匹配时响应——不必等视口变化:
.product-card {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 0.75rem;
background: #fff;
}
.product-card .media {
aspect-ratio: 16 / 10;
border-radius: 0.5rem;
background: #cbd5e1;
}
.product-card .meta {
font-size: 0.875rem;
color: #64748b;
}
@container (min-width: 28rem) {
.product-card {
grid-template-columns: 10rem 1fr;
align-items: center;
}
.product-card .title {
font-size: 1.25rem;
}
}
.product-card 在窄 .rail 里保持单列堆叠。同样 HTML 放进宽 .stage 就解锁双列——同一 markup、同一视口,容器 宽度不同。
命名容器
嵌套容器让你搞不清查的是哪个盒子时,在 @container 后写上名称:
@container stage (min-width: 36rem) {
.product-card {
grid-template-columns: 12rem 1fr auto;
gap: 1.25rem;
}
.product-card .buy {
justify-self: end;
}
}
@container rail (max-width: 18rem) {
.product-card .meta {
display: none;
}
}
@container stage (…) 只关心名为 stage 的祖先。侧栏的紧凑规则不会与主区域的宽松规则打架。
容器查询单位
有了 containment 上下文,cqi(查询容器行内尺寸的 1%)和 cqw(宽度的 1%)等长度让字号与间距跟随 父级,而非视口(vi / vw):
.product-card .title {
font-size: clamp(1rem, 0.85rem + 2.5cqi, 1.5rem);
}
.product-card {
padding: clamp(0.75rem, 2.5cqi, 1.5rem);
}
与 Modern Toolkit 前面课程中的 var()、clamp() 搭配。容器单位测量查询所用的 containment 上下文——适合可复用小组件。
容器与媒体——各管什么?
📊 容器查询与媒体查询
| 你在问什么 | 更合适 | 常用工具 |
|---|---|---|
| 浏览器视口 有多宽? | 页面外壳、导航、整页多栏 | @media (min-width: …) |
| 组件外 这个父级 有多宽? | 卡片、小组件、不等宽槽位里的嵌入 | container-type 后的 @container (min-width: …) |
| 两个都要? | 经常是的 | MQ 管页面;CQ 管槽内组件 |
两个槽位,一个组件
小示意图说明收益——两个容器,一个卡片类:
.page {
display: flex;
gap: 1rem;
align-items: start;
}
.rail {
container-type: inline-size;
container-name: rail;
width: 16rem;
}
.stage {
container-type: inline-size;
container-name: stage;
flex: 1;
min-width: 0;
}
/* Same .product-card class in both slots — @container rules above decide layout */
不必仅为槽宽再拆 .product-card--sidebar 和 .product-card--main。槽位 上报尺寸;卡片听从。
页面媒体查询与组件容器配合
视口查询留给 页面 决策(折叠站点导航、整页改单列)。容器查询留给页面所给槽位里的 组件 决策:
@media (max-width: 40rem) {
.page {
flex-direction: column;
}
.rail {
width: auto;
}
}
@container (min-width: 28rem) {
.product-card {
grid-template-columns: 10rem 1fr;
}
}
小屏手机整页堆叠;宽屏桌面侧栏仍可能窄、主区仍宽——只有容器查询能清楚表达这种差异。
自己动手
- 在卡片外包一层并加
container-type: inline-size;在 DevTools 确认 containment 上下文。 - 写
@container (min-width: 24rem),让卡片从堆叠变为两列。 - 设
container-name: panel,用@container panel (min-width: 30rem)重新指向。 - 用
cqi定标题字号,只改父级宽度(不必改窗口)观察变化。 - 页面外壳保留一条
@media;别把同样逻辑复制进卡片。
常见错误
- 祖先没有
container-type就写@container——没有可测对象 - 用容器查询替换所有媒体查询——页面外壳仍属
@media - 三层嵌套容器搞不清哪个宽度生效——命名并明确指向
- 把视口断点(
48rem)盲目抄进每个小组件——按 槽位 调,不是按设备目录 - 把嵌套(
&、嵌套选择器)和 containment 混为一谈——嵌套整理选择器;容器查询测量盒子
小结
- 容器查询按 父级尺寸 写样式,不只靠视口
- 设置
container-type(常用inline-size);可选container-name便于区分 - 用
@container (min-width: …)/@container name (…)重排后代 - 长度应跟容器走时用
cqi/cqw - Modern Toolkit 下一课:特性查询(
@supports)——按浏览器能力开关样式
🧠 测试您的知识
测试您的知识
通过这个互动测验挑战自己,看看你对这个主题的理解程度如何
📝 说明
- 仔细阅读每个问题
- 为每个问题选择最佳答案
- 您可以随时重新参加测验
- 您的进度将显示在顶部