自CSS诞生以来,响应式设计一直依赖媒体查询(Media Queries)来实现。媒体查询根据视口(viewport)的尺寸来调整样式,这在过去十几年中是响应式设计的基石。然而,随着组件化开发的普及,媒体查询的局限性日益明显:一个组件的样式应该取决于它所在的容器大小,而非整个视口的大小。
CSS容器查询(Container Queries)的出现彻底改变了这一局面。到2026年,容器查询已经获得了所有主流浏览器的全面支持,是时候深入掌握这项革命性的CSS特性了。
考虑一个常见的场景:你的页面中有一个卡片组件,这个卡片可能出现在侧边栏(窄容器)中,也可能出现在主内容区(宽容器)中。
/* 使用媒体查询的问题 */
.card {
display: flex;
flex-direction: column;
padding: 1rem;
}
/* 当视口宽度大于768px时改为横向布局 */
@media (min-width: 768px) {
.card {
flex-direction: row;
}
}
问题在于:当视口宽度大于768px时,即使在窄的侧边栏中,卡片也会变成横向布局——这显然不是我们想要的效果。我们真正需要的是根据卡片自身所在容器的宽度来决定布局方式。
容器查询让组件能够”感知”自身容器的大小,从而做出更精确的布局调整:
/* 使用容器查询 - 组件根据自身容器大小调整 */
.card-container {
container-type: inline-size;
container-name: card;
}
@container card (min-width: 400px) {
.card {
flex-direction: row;
}
}
这样,无论卡片被放在页面的哪个位置,只要它的容器宽度足够,就会自动切换为横向布局。
使用container-type属性将一个元素定义为容器:
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
.main-content {
container-type: inline-size;
container-name: main;
}
container-type有三个可选值:
| 值 | 说明 |
|---|---|
inline-size |
只追踪内联方向(宽度)的变化 |
size |
追踪宽度和高度的变化 |
normal |
默认值,不创建容器 |
性能建议:大多数情况下使用inline-size就足够了,因为高度变化触发的容器查询较少,且size类型可能影响布局性能。
使用@container规则编写基于容器尺寸的样式:
@container (min-width: 400px) {
.product-card {
display: grid;
grid-template-columns: 200px 1fr;
gap: 1.5rem;
}
}
@container (max-width: 399px) {
.product-card {
display: flex;
flex-direction: column;
}
}
当页面中有多个容器时,使用命名容器可以精确控制:
@container sidebar (min-width: 250px) {
.nav-item {
flex-direction: row;
gap: 0.5rem;
}
}
@container card (min-width: 300px) {
.card-content {
columns: 2;
}
}
<div class="card-wrapper">
<div class="card">
<img src="product.jpg" alt="产品图片" class="card-img">
<div class="card-body">
<h3 class="card-title">智能手表 Pro</h3>
<p class="card-desc">搭载最新健康监测传感器</p>
<div class="card-footer">
<span class="price">¥2,999</span>
<button class="btn-buy">立即购买</button>
</div>
</div>
</div>
</div>
.card-wrapper {
container-type: inline-size;
}
.card {
display: flex;
flex-direction: column;
border-radius: 12px;
overflow: hidden;
background: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* 容器宽度大于400px时切换为横向布局 */
@container (min-width: 400px) {
.card {
flex-direction: row;
}
.card-img {
width: 200px;
height: auto;
object-fit: cover;
}
.card-body {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
}
/* 容器宽度大于600px时显示更多信息 */
@container (min-width: 600px) {
.card-desc {
display: block;
}
.card-footer {
margin-top: auto;
}
}
.nav-container {
container-type: inline-size;
}
.nav {
display: flex;
gap: 0.25rem;
overflow-x: auto;
}
@container (min-width: 500px) {
.nav {
overflow-x: visible;
gap: 1rem;
}
.nav-item {
padding: 0.5rem 1rem;
}
}
@container (min-width: 800px) {
.nav {
gap: 2rem;
}
.nav-item::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 2px;
transition: width 0.3s;
}
.nav-item:hover::after {
width: 100%;
}
}
.form-container {
container-type: inline-size;
}
.form-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1rem;
}
@container (min-width: 500px) {
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
}
@container (min-width: 700px) {
.form-row {
grid-template-columns: 1fr 1fr 1fr;
}
.form-actions {
display: flex;
justify-content: flex-end;
gap: 1rem;
}
}
CSS容器查询还引入了新的长度单位,这些单位相对于容器的尺寸:
| 单位 | 说明 |
|---|---|
cqw |
容器宽度的1% |
cqh |
容器高度的1% |
cqi |
容器内联尺寸的1% |
cqb |
容器块尺寸的1% |
cqmin |
cqi和cqb中的较小值 |
cqmax |
cqi和cqb中的较大值 |
.card-wrapper {
container-type: inline-size;
}
.card-title {
/* 字体大小随容器宽度缩放 */
font-size: clamp(1rem, 3cqi, 2rem);
}
.card-img {
/* 图片宽度始终是容器的30% */
width: 30cqi;
}
迁移到容器查询不需要一步到位,可以采用渐进式策略:
container-type/* 迁移前:基于视口的响应式 */
@media (min-width: 768px) {
.widget {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1200px) {
.widget {
grid-template-columns: repeat(3, 1fr);
}
}
/* 迁移后:基于容器的响应式 */
.widget-wrapper {
container-type: inline-size;
}
@container (min-width: 500px) {
.widget {
grid-template-columns: repeat(2, 1fr);
}
}
@container (min-width: 800px) {
.widget {
grid-template-columns: repeat(3, 1fr);
}
}
到2026年,所有主流浏览器都已全面支持容器查询:
对于需要支持旧浏览器的项目,可以使用@supports进行渐进增强:
/* 基础样式(所有浏览器) */
.card {
display: flex;
flex-direction: column;
}
/* 容器查询增强(支持的浏览器) */
@supports (container-type: inline-size) {
.card-wrapper {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
flex-direction: row;
}
}
}
/* 媒体查询回退(不支持的浏览器) */
@supports not (container-type: inline-size) {
@media (min-width: 768px) {
.card {
flex-direction: row;
}
}
}
CSS容器查询代表了响应式设计的一次根本性进化。它将响应式的关注点从”视口”转移到了”组件”,使得真正的组件化响应式设计成为可能。随着浏览器支持的全面成熟,现在是学习和采用容器查询的最佳时机。
在未来的前端开发中,容器查询将成为组件库和设计系统的标配特性。掌握容器查询,不仅能提升你的CSS技能,更能帮助你构建出更灵活、更可复用、更优雅的组件系统。
💡 推荐工具:正在寻找高质量的开发工具和模板?看看这些: