响应式设计是现代 Web 开发的基石。长期以来,媒体查询(Media Queries) 是实现响应式布局的唯一工具。但随着组件化开发的普及,CSS 容器查询(Container Queries)的出现为响应式设计带来了全新的思路。本文将从核心概念、语法差异、作用域、使用场景等多个维度,全面对比容器查询与媒体查询的区别。
什么是媒体查询?
媒体查询(@media)是 CSS 中最经典的响应式技术,通过检测视口(viewport)的尺寸、设备类型、分辨率等条件来应用不同的样式。
/* 当视口宽度小于 768px 时生效 */
@media (max-width: 768px) {
.card {
flex-direction: column;
padding: 1rem;
}
}媒体查询响应的是整个浏览器窗口的变化,而非单个元素所在容器的变化。
什么是容器查询?
容器查询(@container)是 CSS 较新的特性,它允许根据父容器的尺寸而非视口尺寸来应用样式。这意味着组件可以根据自身所在的容器空间来调整布局。
/* 声明容器 */
.card-wrapper {
container-type: inline-size;
container-name: card-container;
}
/* 当容器宽度小于 400px 时生效 */
@container card-container (max-width: 400px) {
.card {
flex-direction: column;
padding: 1rem;
}
}核心区别对比
1. 检测目标不同
| 维度 | 媒体查询 @media | 容器查询 @container |
|---|---|---|
| 检测对象 | 视口(viewport) | 父容器(container) |
| 作用范围 | 全局 | 组件级 |
| 响应粒度 | 页面级 | 元素级 |
媒体查询始终以浏览器视口为参照,而容器查询以被声明的祖先容器为参照。这是两者最本质的区别。
2. 组件复用性
媒体查询的局限:同一个卡片组件放在页面侧边栏(窄区域)和主内容区(宽区域)时,无法根据所在区域的宽度自动调整布局。你只能针对视口宽度写死样式,导致组件在不同位置可能显示不理想。
容器查询的优势:卡片组件只需要声明自己的容器查询规则,无论被放在侧边栏还是主内容区,都能根据实际可用空间自动适配。这极大提升了组件的可复用性。
<!-- 同一个组件,放在不同宽度的容器中,自动适配 -->
<aside style="width: 300px">
<div class="card-wrapper">
<div class="card">...</div>
</div>
</aside>
<main style="width: 900px">
<div class="card-wrapper">
<div class="card">...</div>
</div>
</main>3. 语法结构
媒体查询直接使用 @media 关键字,不需要额外声明:
@media (min-width: 768px) { /* ... */ }容器查询需要两步——先声明容器,再编写查询规则:
/* 第一步:声明容器 */
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
/* 第二步:查询容器 */
@container sidebar (min-width: 400px) { /* ... */ }4. 支持的查询条件
- 媒体查询:支持宽度、高度、设备类型(
screen/print)、分辨率(dpi)、颜色能力、悬停能力(hover)、 prefers-color-scheme 等。 - 容器查询:目前主要支持尺寸查询(
inline-size、block-size)和样式查询(style()),条件类型相对有限,但正在扩展中。
5. 性能考量
- 媒体查询:浏览器在视口尺寸变化时(如窗口缩放、设备旋转)重新计算匹配规则,性能开销较小且已被高度优化。
- 容器查询:需要浏览器追踪容器尺寸变化,在某些复杂布局中可能引入额外的布局计算。但在现代浏览器中,性能差异通常可以忽略。
实际场景选择指南
适合使用媒体查询的场景
- 页面整体布局切换(如单栏变多栏)
- 针对打印样式(
@media print) - 针对设备特性(暗色模式、减少动画偏好)
- 全局导航栏、页脚等非组件化的页面级元素
- 需要检测设备类型或分辨率时
/* 全局暗色模式 */
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--fg: #f0f0f0;
}
}
/* 打印样式 */
@media print {
nav, footer { display: none; }
}适合使用容器查询的场景
- 可复用的 UI 组件(卡片、列表、表单、导航)
- 组件库和设计系统中的通用组件
- 组件可能被放置在页面不同位置、不同宽度的区域
- 嵌套布局中的自适应需求
- Widget、嵌入式内容、第三方组件集成
/* 可复用的卡片组件 */
.product-card-wrapper {
container-type: inline-size;
}
@container (min-width: 500px) {
.product-card {
display: grid;
grid-template-columns: 200px 1fr;
}
}
@container (max-width: 499px) {
.product-card {
display: flex;
flex-direction: column;
}
}两者可以共存
容器查询并不是要取代媒体查询,而是互补关系。在实际项目中,最佳实践是:
- 用 媒体查询 处理页面级响应(整体布局、设备特性、用户偏好)
- 用 容器查询 处理组件级响应(组件内部布局自适应)
/* 页面级:媒体查询 */
@media (min-width: 1024px) {
.page-layout {
display: grid;
grid-template-columns: 300px 1fr;
}
}
/* 组件级:容器查询 */
.sidebar-widget {
container-type: inline-size;
}
@container (max-width: 280px) {
.widget-title {
font-size: 0.875rem;
}
}两者可以共存
- 媒体查询:所有主流浏览器全面支持,包括 IE9+。
- 容器查询:Chrome 105+、Firefox 110+、Safari 16+ 均已支持。对于需要兼容旧浏览器的项目,可配合
@supports做渐进增强。
/* 渐进增强方案 */
.card-wrapper {
/* 默认样式(移动优先) */
display: flex;
flex-direction: column;
}
@supports (container-type: inline-size) {
.card-wrapper {
container-type: inline-size;
}
@container (min-width: 500px) {
.card-wrapper .card {
flex-direction: row;
}
}
}总结
| 对比项 | 媒体查询 @media | 容器查询 @container |
|---|---|---|
| 检测对象 | 视口 | 容器 |
| 粒度 | 页面级 | 组件级 |
| 组件复用 | 较弱 | 极强 |
| 语法复杂度 | 简单 | 需声明容器 |
| 查询条件 | 丰富 | 逐步扩展中 |
| 兼容性 | 极广 | 现代浏览器 |
| 最佳场景 | 全局布局、设备特性 | 可复用组件 |
容器查询代表了 CSS 响应式设计从"页面驱动"到"组件驱动"的演进。理解两者的区别和适用场景,能帮助你在项目中做出更合理的技术选择,构建出真正灵活、可复用的响应式组件。