为什么需要 Container Queries?
传统响应式设计依赖 @media 查询,它只能根据视口(viewport)尺寸调整样式。但现代 UI 中,一个组件可能在侧边栏、弹窗、全屏页等不同宽度的容器里复用——媒体查询完全无能为力。
1
2
3
4
|
/* 传统方式:依赖视口宽度 */
@media (max-width: 600px) {
.card { flex-direction: column; }
}
|
上面这段代码的问题在于:即使 .card 在 400px 宽的侧边栏里,它也会根据 600px 以下的视口规则变成纵向排列,这太死板了。
CSS Container Queries 解决了这个痛点——它让组件根据自身父容器的尺寸响应,真正做到组件级自适应。
基础语法三步走
第一步:定义容器
给父元素设置 container-type,告诉浏览器它是一个查询容器:
1
2
3
4
5
|
/* 最简单的容器定义 */
.card-container {
container-type: inline-size; /* 仅监听宽度变化 */
/* container-type: size; */ /* 同时监听宽高(较少用) */
}
|
inline-size 是最常用的值,它只监听容器的内联方向(对中文/英文就是宽度),性能更好。
你也可以给容器命名,以便在多个容器中精确定位:
1
2
3
4
5
6
7
8
9
|
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
/* 简写 */
.main-area {
container: main / inline-size;
}
|
第二步:编写容器查询
定义好容器后,在子孙元素中使用 @container:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@container (min-width: 500px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
}
}
/* 命名容器的查询 */
@container sidebar (max-width: 300px) {
.card-title {
font-size: 0.9rem;
}
}
|
第三步:完整的实战示例
一个在产品列表、推荐侧栏、购物车弹窗中都能自适应布局的商品卡片:
1
2
3
4
5
6
7
8
9
10
11
|
<div class="product-shelf">
<div class="product-card">
<img src="product.jpg" alt="商品图" class="product-image" />
<div class="product-info">
<h3 class="product-name">无线降噪耳机</h3>
<p class="product-desc">Hi-Res 音质,40小时续航</p>
<span class="product-price">¥499</span>
<button class="buy-btn">加入购物车</button>
</div>
</div>
</div>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
.product-shelf {
container-type: inline-size;
}
.product-card {
display: flex;
gap: 1rem;
padding: 1rem;
border-radius: 8px;
background: #fff;
}
.product-image {
width: 120px;
height: 120px;
object-fit: cover;
border-radius: 8px;
}
/* 容器窄于 400px:上方图片,下方文字(纵向堆叠) */
@container (max-width: 400px) {
.product-card {
flex-direction: column;
}
.product-image {
width: 100%;
height: 200px;
}
.product-name {
font-size: 1rem;
}
.product-desc {
display: none; /* 空间不够,隐藏详情 */
}
}
/* 容器中等宽度:保留描述,调整字号 */
@container (min-width: 401px) and (max-width: 700px) {
.product-price {
font-size: 1.1rem;
color: #e74c3c;
}
.buy-btn {
padding: 0.4rem 0.8rem;
font-size: 0.85rem;
}
}
|
容器查询长度单位
Container Queries 还引入了 cq 单位,作用类似 vw/vh,但参照的是容器尺寸而非视口:
| 单位 |
参照 |
cqw |
容器宽度的 1% |
cqh |
容器高度的 1% |
cqi |
容器内联方向尺寸的 1%(推荐) |
cqb |
容器块方向尺寸的 1% |
cqmin |
cqi 和 cqb 中较小的值 |
cqmax |
cqi 和 cqb 中较大的值 |
实战例子:让字体随容器动态缩放
1
2
3
|
.card-title {
font-size: clamp(0.875rem, 3cqi, 1.5rem);
}
|
这段代码让标题字号在容器宽度的 3% 和上下限之间自适应——容器越宽字越大,缩窄时自动减小,完美响应式字体。
实战:响应式数据表格
表格在不同宽度容器中呈现截然不同的形态,是 Container Queries 的最佳场景:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
.data-table-wrapper {
container-type: inline-size;
}
/* 宽容器:标准表格 */
@container (min-width: 600px) {
.data-table {
display: table;
width: 100%;
border-collapse: collapse;
}
.data-table th,
.data-table td {
padding: 0.75rem;
border-bottom: 1px solid #eee;
}
}
/* 中等容器:卡片式表格 */
@container (min-width: 400px) and (max-width: 599px) {
.data-table {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5rem;
}
.data-table tr {
display: contents;
}
.data-table th { display: none; }
.data-table td {
padding: 0.5rem;
background: #f8f9fa;
border-radius: 4px;
}
}
/* 窄容器:列表式 */
@container (max-width: 399px) {
.data-table, .data-table tbody {
display: block;
}
.data-table tr {
display: block;
margin-bottom: 1rem;
padding: 0.75rem;
background: #fff;
border: 1px solid #eee;
border-radius: 8px;
}
.data-table th { display: none; }
.data-table td {
display: flex;
justify-content: space-between;
padding: 0.25rem 0;
}
/* 用 data-label 属性模拟表头 */
.data-table td::before {
content: attr(data-label);
font-weight: 600;
color: #666;
}
}
|
对应的 HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<div class="data-table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>姓名</th><th>部门</th><th>职位</th><th>入职时间</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="姓名">张三</td>
<td data-label="部门">研发部</td>
<td data-label="职位">高级工程师</td>
<td data-label="入职时间">2024-03-15</td>
</tr>
<!-- 更多行... -->
</tbody>
</table>
</div>
|
注意事项与最佳实践
-
不要对每个元素都设容器:容器定义有性能开销,只在真正需要组件级响应的父级设置。
-
容器不能查询自身:@container 查的是最近的祖先容器,不能查自身。需要自引用时用 ResizeObserver 配合 JS。
-
容器链只认一个:嵌套容器时,@container 默认向上找到最近的容器。想精确控制用 container-name。
-
兼容性:2026 年所有主流浏览器早已完全支持 Container Queries(Chrome 105+, Safari 16+, Firefox 110+),生产环境可以放心使用。
-
配合 Grid/Flexbox 更强大:Container Queries + CSS Grid + clamp() 三件套,可以写出不需要任何 JS 就能完美自适应的复杂组件。
小结
Container Queries 是 CSS 这几年最具革命性的特性之一。它把"响应式"的责任从页面级下放到组件级,让真正的组件化开发成为可能。下次再遇到「这个组件在侧边栏和主页中布局不同」的需求时,别再写两套组件逻辑了——交给 @container 吧。