CSS 容器查询
容器查询解决的是什么问题
传统的响应式设计基于视口(viewport)来调整布局。当视口宽度小于某个阈值时,整页布局发生变化。但这种方法是页面级别的,不是组件级别的。
想象一个卡片组件:它在页面主内容区显示时是宽的,在侧边栏显示时是窄的,在弹窗中显示时又不同。传统的媒体查询无法让同一个组件在不同容器中自动适应——除非你为每种容器写不同的 class。
容器查询让组件能够根据自身容器(而不是视口)的尺寸来调整样式,实现了真正的组件级响应式。
面试定位:容器查询是 CSS 的重大新特性(2023+ 才在主流浏览器稳定支持)。面试官通过候选人对容器查询机制的理解和应用场景的判断,问的是对新 CSS 特性的掌握程度。
容器查询的基础语法
1. 定义容器
/* 定义一个容器 */
.card-container {
container-type: inline-size; /* 监听行内轴尺寸变化 */
container-name: card; /* 可选:命名容器 */
}
/* 简写 */
.card-container {
container: card / inline-size; /* name / type */
}
2. 使用 @container 查询
/* 根据容器宽度查询 */
@container card (min-width: 400px) {
.card {
flex-direction: row;
}
.card-image {
width: 50%;
}
}
/* 无命名容器的查询 */
@container (min-width: 300px) {
.card {
padding: 1.5rem;
}
}
container-type 的类型
.container {
/* size:容器成为块级容器,查询两个轴 */
container-type: size;
/* inline-size:只查询行内轴(常用) */
container-type: inline-size;
/* style:查询样式相关的容器状态 */
container-type: style;
/* state:查询容器状态(如悬停) */
container-type: state;
}
为什么常用 inline-size 而不是 size
/* size 会限制内部布局,可能导致意外 */
.size-container {
container-type: size;
height: 300px; /* 必须设置高度 */
}
.size-container {
container-type: inline-size; /* 更灵活,不限制块轴 */
}
实战:卡片组件的容器查询
基础结构
<article class="card">
<div class="card-image">
<img src="photo.jpg" alt="风景照">
</div>
<div class="card-content">
<h2>标题</h2>
<p>描述文本...</p>
<button>操作按钮</button>
</div>
</article>
容器查询样式
/* 1. 定义容器 */
.card-wrapper {
container: card / inline-size;
}
/* 2. 默认样式(小容器) */
.card {
display: flex;
flex-direction: column;
}
.card-image img {
width: 100%;
aspect-ratio: 16/9;
object-fit: cover;
}
.card-content {
padding: 1rem;
}
/* 3. 容器宽度 >= 400px 时 */
@container card (min-width: 400px) {
.card {
flex-direction: row;
}
.card-image {
width: 40%;
}
.card-image img {
width: 100%;
height: 100%;
aspect-ratio: auto;
}
.card-content {
padding: 1.5rem;
flex: 1;
}
}
/* 4. 容器宽度 >= 600px 时(大屏布局) */
@container card (min-width: 600px) {
.card {
gap: 2rem;
}
.card-image {
width: 50%;
}
.card-content h2 {
font-size: 1.5rem;
}
}
容器查询与媒体查询的对比
| 特性 | 容器查询 | 媒体查询 |
|---|---|---|
| 查询对象 | 组件容器 | 视口 |
| 组件自治 | 组件自己感知容器 | 需要外部 class 控制 |
| 复用性 | 高(同一组件多处使用) | 低(依赖页面上下文) |
| 浏览器支持 | 2023+ 稳定支持 | 全部支持 |
/* 媒体查询:组件在不同位置需要不同的 class */
.sidebar .card { /* ... */ }
.main .card { /* ... */ }
.modal .card { /* ... */ }
/* 容器查询:组件自己感知容器 */
.card-wrapper { container: card / inline-size; }
@container card (min-width: 400px) { /* ... */ }
容器查询的单位
容器查询引入了新的相对单位:
.container {
container-type: inline-size;
}
/* cqi = 容器行内尺寸的 1% */
.cqi-unit {
font-size: 5cqi; /* 容器宽度的 5% */
}
/* cqb = 容器块轴尺寸的 1% */
.cqb-unit {
font-size: 5cqb; /* 容器高度的 5% */
}
/* cqw = 容器宽度的 1% */
.cqw-unit {
width: 20cqw;
}
/* cqh = 容器高度的 1% */
.cqh-unit {
height: 10cqh;
}
/* cqmin = cqw 和 cqh 中较小的 */
.cqmin-unit {
padding: 2cqmin;
}
面试高频问题
Q: 容器查询和媒体查询有什么区别?
回答要点:媒体查询基于视口尺寸来调整样式,容器查询基于组件所在容器的尺寸。容器查询实现了组件级别的响应式——同一个组件在不同容器中可以自动适应,不需要外部 class 控制。媒体查询适合页面级布局,容器查询适合组件级布局。
Q: 为什么 container-type: inline-size 比 size 更常用?
回答要点:size 类型会限制容器的块轴尺寸(通常需要设置 height),这可能限制内部布局的灵活性。inline-size 只监听行内轴(通常是宽度),不限制块轴,更适合大多数组件的响应式需求。
Q: 容器查询有哪些新单位?
回答要点:容器查询引入了 cqi(容器行内尺寸的 1%)、cqb(容器块轴尺寸的 1%)、cqw(容器宽度)、cqh(容器高度)、cqmin(取 cqw 和 cqh 较小者)。这些单位允许组件的字体和间距相对于容器尺寸进行响应式调整。