一、为什么我们需要容器查询?
长期以来,CSS开发者一直依赖@media 媒体查询来实现响应式设计。然而,媒体查询有一个根本性的局限——它只关注视口(viewport)宽度,而非组件所在的实际容器空间。
举个常见场景:一个卡片组件在侧边栏中看起来很正常,但当它被放到主内容区变宽的容器中时,卡片内部的布局可能就不够理想了。媒体查询无法解决这个问题,因为它不知道当前组件"住在"哪个容器里。
CSS容器查询(Container Queries)正是为了解决这一痛点而生。它允许我们根据父容器的大小来设置子元素的样式,真正实现"组件级别的响应式设计"。
二、浏览器支持与渐进增强
截至2025年底,CSS容器查询已得到主流浏览器的全面支持:
- Chrome 105+ ✅
- Firefox 110+ ✅
- Safari 16+ ✅
- Edge 105+ ✅
- 移动端浏览器:iOS Safari 16+、Chrome Android 105+ ✅
支持率已超过 95%,可以放心在生产环境中使用。对于确实需要兼容旧浏览器的项目,可以使用 CSS 的 @supports 特性来实现渐进增强:
@supports (container-type: inline-size) {
/* 容器查询支持的样式 */
}
@supports not (container-type: inline-size) {
/* 回退到媒体查询的方案 */
}
三、核心概念:Container Name 与 Container Type
容器查询的工作原理可以拆解为三个步骤:定义容器 → 命名容器 → 查询容器。
3.1 定义容器
使用 container-type 属性将一个元素定义为查询容器:
.card-wrapper {
container-type: inline-size;
}
container-type 有两个值:
- inline-size:基于行内方向(水平方向)的尺寸创建查询,最常用
- size:基于行内和块级方向创建查询,会创建独立的布局、样式和尺寸 containment
- normal:元素不作为查询容器,但仍是样式查询的容器
3.2 命名容器(可选但推荐)
使用 container-name 可以给容器命名,实现更精确的查询定向:
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
.main-content {
container-type: inline-size;
container-name: main;
}
/* 简写形式 */
.card-wrapper {
container: card / inline-size;
}
通过命名,可以区分嵌套容器中的查询目标:
@container sidebar (max-width: 300px) {
.card { flex-direction: column; }
}
@container main (min-width: 600px) {
.card { flex-direction: row; }
}
四、@container 查询语法详解
容器查询的语法与媒体查询非常相似,但使用的是 @container 关键字:
/* 基础语法 */
@container (min-width: 400px) {
.card-title { font-size: 1.25rem; }
}
/* 带容器名 */
@container card (min-width: 600px) {
.card__image { width: 40%; }
.card__content { width: 60%; }
}
/* 范围语法(Level 4+) */
@container card (400px <= width <= 800px) {
.card { padding: 1rem; }
}
/* 逻辑组合 */
@container card (min-width: 500px) and (max-height: 800px) {
.card { grid-template-columns: 1fr 2fr; }
}
注意:容器查询不支持查询高度方向(使用 container-type: size 时可以查询),也不支持基于orientation或aspect-ratio的查询。
五、实战案例:自适应卡片组件
下面我们通过一个完整的实战案例,展示如何用容器查询替代传统媒体查询,打造一个真正"智能"的自适应卡片。
HTML 结构
文章标题
文章摘要描述...
CSS 容器查询样式
/* 定义查询容器 */
.card-container {
container-type: inline-size;
container-name: card;
}
/* 基础样式(移动优先) */
.card {
display: flex;
flex-direction: column;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
background: #fff;
}
.card__image {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.card__body {
padding: 1rem;
}
.card__title {
font-size: 1rem;
font-weight: 700;
margin: 0 0 0.5rem;
line-height: 1.4;
}
.card__excerpt {
font-size: 0.875rem;
color: #666;
margin: 0 0 0.75rem;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.card__meta {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.75rem;
color: #999;
}
/* 中等容器(≥450px):横向布局 */
@container card (min-width: 450px) {
.card {
flex-direction: row;
}
.card__image {
width: 40%;
aspect-ratio: 1;
min-height: 100%;
}
.card__body {
flex: 1;
display: flex;
flex-direction: column;
}
.card__title {
font-size: 1.125rem;
}
}
/* 大容器(≥700px):更丰富的布局 */
@container card (min-width: 700px) {
.card {
flex-direction: column;
}
.card__image {
width: 100%;
aspect-ratio: 21 / 9;
}
.card__body {
padding: 1.5rem;
}
.card__title {
font-size: 1.375rem;
margin-bottom: 0.75rem;
}
.card__excerpt {
font-size: 0.9375rem;
-webkit-line-clamp: 3;
}
}
上述方案的强大之处在于:.card-container 无论放在页面中的任何位置(侧边栏、主内容、全屏宽度卡片),卡片都会自动根据其所处容器的实际可用宽度来调整自身布局——这才是真正组件级别的自适应。
六、容器查询 vs 媒体查询:何时该用哪个?
以下是选择指南:
- 用媒体查询(@media)的场景::
- 页面整体布局变化(如导航栏从水平变垂直汉堡菜单)
- 全局字体基准大小调整
- 根据设备特性(print、prefers-color-scheme)调整样式
- 用容器查询(@container)的场景:
- 可复用的UI组件需要根据其所在容器自适应
- 微前端中不同子应用共用同一组件库
- 设计系统/组件库开发(让组件自己"感知"所处环境)
- 用户可拖拽调整面板宽度的 Dashboard 界面
七、与 :has() 选择器的组合威力
CSS容器查询还可以与 :has() 选择器结合,解决更复杂的布局问题。例如:容器内有图片时切换布局方向:
/* 当卡片包含图片时使用横向布局 */
.card:has(.card__image) {
flex-direction: row;
}
/* 容器宽度足够且有图片时:图片占比更大 */
@container card (min-width: 500px) {
.card:has(.card__image) .card__image {
width: 50%;
}
}
八、容器查询单位(cqw、cqh 等)
容器查询还引入了新的容器相对长度单位,它们相对于查询容器的尺寸:
- cqw:容器宽度的 1%(1cqw = 1% of container width)
- cqh:容器高度的 1%
- cqi:容器行内尺寸的 1%
- cqb:容器块级尺寸的 1%
- cqmin:cqi 和 cqb 中较小的值
- cqmax:cqi 和 cqb 中较大的值
这些单位的妙用在于字体大小可以跟随容器而非视口缩放:
.card__title {
/* 标题字体随容器宽度等比缩放 */
font-size: clamp(0.875rem, 3cqw + 0.5rem, 1.5rem);
}
.card__icon {
/* 图标尺寸随容器宽度等比缩放 */
width: 8cqw;
height: 8cqw;
}
九、性能考量与最佳实践
容器查询的性能开销很小,但以下几点值得注意:
- 不要滥用 container-type: size ——它会创建完整的 containment,增加渲染成本。大多数场景用 inline-size 就够
- 避免过深的容器嵌套 ——会影响查询性能
- 不要将 body 或 html 设为查询容器 ——没有必要,用媒体查询更合适
- 命名容器时保持语义化 ——
card、sidebar、dashboard-panel比c1、c2更利于维护
十、总结
CSS容器查询标志着CSS从"基于视口的设计"向"基于组件的设计"的范式转变。它是构建真正响应式、可复用UI组件体系的基石技术之一。
核心优势回顾:
- ✅ 组件根据所在容器自适应,而非仅根据视口宽度
- ✅ 与媒体查询不冲突,可以混用
- ✅ 渐进增强友好,不支持时优雅降级
- ✅ 引入 cqw/cqh 等新单位,让字体、图标也能等比缩放
随着 Safari 和 Firefox 的全面跟进,容器查询已经在2025年成为前端开发的标配技能。从今天开始,在你的下一个项目中使用 @container,让组件真正学会"看容器脸色行事"。

发表评论 取消回复