以前写响应式组件,总要根据视口宽度写一堆
@media,代码又臭又长。现在 Container Queries 让组件根据父容器尺寸响应,代码直接减半。本文讲透语法 + 5 个可直接复用的案例。
一、Container Queries 解决了什么问题?
@media 媒体查询基于视口宽度。这导致一个组件在不同父容器下无法独立响应------同样的卡片,在侧边栏和主内容区需要两套样式或者额外类名。
Container Queries 允许你定义:当父容器达到某个宽度时,子元素改变布局。
css
/* 以前:基于视口,无法区分卡片在哪个容器里 */
@media (min-width: 600px) {
.card { display: flex; }
}
/* 现在:基于父容器宽度 */
@container (min-width: 300px) {
.card { display: flex; }
}
二、基础语法(三步搞定)
2.1 定义容器
css
.sidebar {
container-type: inline-size; /* 监听内联方向(宽度)变化 */
container-name: sidebar; /* 可选,给容器起名 */
}
container-type: inline-size最常用,表示根据宽度变化。- 也可以
size(宽高都监听)或normal(不监听)。
2.2 使用 @container
css
@container (min-width: 300px) {
.card-title {
font-size: 1.5rem;
}
}
如果只有一个容器,可以直接写条件。如果有多个容器,用 container-name 限定:
css
@container sidebar (min-width: 300px) {
/* 只对 sidebar 容器内的元素生效 */
}
2.3 组合与范围
css
@container (100px <= width < 300px) {
/* 容器宽度在 100px 到 300px 之间 */
}
三、与 @media 对比(代码量减少 50%)
| 场景 | 传统 @media 做法 | Container Queries 做法 |
|---|---|---|
| 卡片在侧边栏时垂直,在主区域时水平 | 写两套类名或全局判断 | 父容器定义后,卡片内一套规则自动适配 |
| 仪表盘小部件适应不同格子尺寸 | 根据视口断点统一控制 | 每个小部件独立响应自己的容器 |
代码对比:
html
<!-- 以前:需要额外类名 -->
<div class="sidebar">
<div class="card vertical"></div>
</div>
<div class="main">
<div class="card horizontal"></div>
</div>
css
/* 以前:手动控制 */
.card.vertical { flex-direction: column; }
.card.horizontal { flex-direction: row; }
/* Container Queries:一套规则 */
.card {
container-type: inline-size;
}
@container (min-width: 400px) {
.card { flex-direction: row; }
}
@container (max-width: 399px) {
.card { flex-direction: column; }
}
四、5 个实战案例(可直接复制)
案例 1:卡片组件根据容器宽度切换布局
html
<div class="card-container">
<div class="card">
<img src="photo.jpg" alt="">
<div class="card-body">
<h3>标题</h3>
<p>描述文字</p>
</div>
</div>
</div>
css
.card-container {
container-type: inline-size;
}
.card {
display: flex;
flex-direction: column;
gap: 1rem;
}
@container (min-width: 350px) {
.card {
flex-direction: row;
align-items: center;
}
.card img {
width: 40%;
}
}
案例 2:侧边栏与主内容区共享同一卡片组件
css
/* 不需要任何额外代码,卡片自己响应父容器宽度 */
.sidebar { container-type: inline-size; width: 280px; }
.main { container-type: inline-size; width: 800px; }
/* 卡片规则如上,当父容器<350px时垂直,>350px时水平 */
案例 3:仪表盘小部件矩阵
html
<div class="dashboard">
<div class="widget" style="width: 200px">...</div>
<div class="widget" style="width: 400px">...</div>
<div class="widget" style="width: 200px">...</div>
</div>
css
.widget {
container-type: inline-size;
}
.widget-content {
font-size: 12px;
}
@container (min-width: 250px) {
.widget-content {
font-size: 16px;
display: flex;
gap: 1rem;
}
}
案例 4:商品列表切换行列(类似 Grid 与 Flex 混合)
css
.product-list {
container-type: inline-size;
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.product-item {
flex: 1 1 200px;
}
@container (max-width: 500px) {
.product-item {
flex-basis: 100%; /* 小于500px时每行一个 */
}
}
案例 5:自适应导航栏(折叠菜单)
html
<nav class="navbar">
<div class="logo">Logo</div>
<ul class="nav-links">
<li>首页</li>
<li>产品</li>
<li>关于</li>
</ul>
</nav>
css
.navbar {
container-type: inline-size;
display: flex;
justify-content: space-between;
}
.nav-links {
display: flex;
gap: 1rem;
}
@container (max-width: 500px) {
.navbar {
flex-direction: column;
}
.nav-links {
flex-direction: column;
margin-top: 0.5rem;
}
}
五、浏览器兼容性与降级方案
支持情况(截至 2026-06):
- Chrome 105+ ✅
- Firefox 110+ ✅
- Safari 16+ ✅
- Edge 105+ ✅
如果需要兼容旧浏览器 ,使用 @supports 渐进增强:
css
/* 降级:默认样式(例如始终垂直) */
.card {
flex-direction: column;
}
/* 支持 Container Queries 时覆盖 */
@supports (container-type: inline-size) {
.card-container {
container-type: inline-size;
}
@container (min-width: 350px) {
.card {
flex-direction: row;
}
}
}
六、总结
- Container Queries 让组件根据父容器而非视口响应,实现真正的组件级响应式。
- 语法简单:
container-type+@container。 - 5 个案例覆盖卡片、侧边栏、仪表盘、商品列表、导航栏。
- 兼容性已可投入生产,配合
@supports安全降级。
文中所有代码均可直接复制到项目中。以后写响应式组件,先问自己:这个样式是由视口决定,还是由父容器决定?
讨论 :你在开发中遇到过哪些因 @media 全局断点导致的组件复用困难?欢迎留言分享。