CSS Container Queries 容器查询入门教程
一句话理解:
@media查询浏览器窗口 宽度,@container查询某个容器宽度。
一、为什么需要 Container Queries?
场景:组件放到不同位置,表现应该不同
想象一个卡片组件:
html
<!-- 侧边栏里的卡片,可用空间很窄 -->
<aside class="sidebar">
<div class="card">...</div>
</aside>
<!-- 主内容区的卡片,可用空间很宽 -->
<main class="content">
<div class="card">...</div>
</main>
用 @media 的问题:
css
/* 大屏下所有卡片都是横向两栏 */
@media (min-width: 768px) {
.card { display: grid; grid-template-columns: 1fr 2fr; }
}
问题:侧边栏里的卡片宽度只有 200px,但 @media 认为"屏幕很大,应该是大屏模式",导致卡片内容溢出。
用 @container 的解决:
css
.card-wrapper {
container: card / inline-size; /* 声明这个容器是可查询的 */
}
@container card (min-width: 400px) {
.card { grid-template-columns: 1fr 2fr; } /* 宽容器 → 横向两栏 */
}
@container card (max-width: 399px) {
.card { flex-direction: column; } /* 窄容器 → 垂直堆叠 */
}
卡片根据自身所在容器的实际宽度自适应,放到哪里都能正确显示。
二、@container vs @media 对比
| 维度 | @media 媒体查询 |
@container 容器查询 |
|---|---|---|
| 查询对象 | 浏览器视口(屏幕) | 某个具体元素的容器 |
| 使用方式 | @media (min-width: 400px) |
@container card (min-width: 400px) |
| 最佳场景 | 页面级布局(PC/平板/手机) | 组件级布局(组件自适应) |
| 浏览器兼容 | ✅ 全部支持 | Chrome 105+、Firefox 110+、Safari 16+ |
| 需要额外标记 | 不需要 | 需要给容器加 container-type |
三、完整示例
3.1 HTML 结构
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Container Queries Demo</title>
<style>
body {
padding: 30px;
font-family: system-ui, sans-serif;
}
/* ========== 步骤 1:定义容器 ========== */
.card-wrapper {
/* 简写形式,相当于:
container-type: inline-size;
container-name: card;
*/
container: card / inline-size;
/* 调试辅助:可以拖拽调整宽度 */
resize: horizontal;
overflow: auto;
width: 450px;
max-width: 100%;
border: 1px solid #aaa;
padding: 12px;
}
.card {
gap: 14px;
}
/* ========== 步骤 2:定义容器查询规则 ========== */
/* 容器宽度 >=400px:grid 两栏布局 */
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 1fr 2fr;
}
}
/* 容器宽度 <=399px:垂直 flex 堆叠 */
@container card (max-width: 399px) {
.card {
display: flex;
flex-direction: column;
}
}
.card-left {
background-color: #cce0ff;
padding: 16px;
border-radius: 6px;
}
.card-right {
background-color: #e6f0ff;
padding: 16px;
border-radius: 6px;
}
</style>
</head>
<body>
<h4>拖动盒子右侧边框,改变容器宽度,观察布局切换</h4>
<div class="card-wrapper">
<div class="card">
<div class="card-left">侧边信息栏</div>
<div class="card-right">
主体内容区域<br>
容器 >=400px 横向两栏;<400px 垂直堆叠
</div>
</div>
</div>
</body>
</html>
3.2 关键概念图解
arduino
┌─────────────────────────────────────────┐
│ .card-wrapper │
│ (container: card / inline-size) ◄──── 容器查询基准
│ ┌─────────────────────────────────┐ │
│ │ .card │ │
│ │ ┌──────────┐ ┌────────────┐ │ │
│ │ │ .card- │ │ .card-right│ │ │
│ │ │ left │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ └──────────┘ └────────────┘ │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
▲
└─ @container card (min-width: 400px)
根据 .card-wrapper 的宽度决定 .card 的布局
四、使用步骤(三步走)
步骤 1:在容器元素上声明
css
.card-wrapper {
container: card / inline-size;
/*
完整写法:
container-type: inline-size; ← 基于宽度的查询
container-name: card; ← 给容器起个名字
*/
}
属性说明:
container-type: inline-size--- 基于容器宽度做查询container-type: size--- 基于容器宽高都做查询(一般不用)container-name: card--- 给容器命名,供@container引用
步骤 2:编写容器查询规则
css
@container card (min-width: 400px) {
/* 当名为 "card" 的容器宽度 >=400px 时生效 */
.card {
display: grid;
grid-template-columns: 1fr 2fr;
}
}
步骤 3:在容器内放置子元素
html
<div class="card-wrapper"> <!-- 容器(查询基准) -->
<div class="card"> <!-- 内部元素(应用样式) -->
<div class="card-left">...</div>
<div class="card-right">...</div>
</div>
</div>
五、容器写在哪?------写在直接父级最好
| 写法 | 查询基准 | 推荐度 | 说明 |
|---|---|---|---|
| 直接父级 | 组件自身的包裹层 | ⭐ 推荐 | 组件级响应式,放哪都能自适应 |
| 更外层 | 页面布局区域 | 特定场景 | 统一控制多个组件 |
| 自身 | 元素自己 | ❌ 不推荐 | 容易循环依赖 |
最佳实践:
@media管页面整体框架(侧边栏显示/隐藏、主内容区宽度)@container管组件内部细节(卡片如何排列、文字大小调整)
六、常见问题
Q1:为什么样式不生效?
检查清单:
-
容器是否声明了
container-type?css/* ❌ 错误:直接写 @container,但没有声明容器 */ /* ✅ 正确:先声明容器 */ .card-wrapper { container: card / inline-size; } -
容器名称是否匹配?
css/* 声明时叫 card */ container: card / inline-size; /* 查询时也要叫 card */ @container card (min-width: 400px) { } -
CSS 属性是否用了全角字符?
css/* ❌ 错误:全角连字符 */ container‑type: inline‑size; /* ✅ 正确:ASCII 连字符 */ container-type: inline-size; -
浏览器是否支持?Chrome 需 105+,Safari 需 16+。
Q2:可以简写吗?
可以,用 container 简写属性:
css
/* 完整写法 */
.card-wrapper {
container-type: inline-size;
container-name: card;
}
/* 简写 */
.card-wrapper {
container: card / inline-size;
}
Q3:和 @media 一起用会冲突吗?
不会冲突,两者互补:
css
/* 页面级:根据屏幕宽度调整侧边栏 */
@media (min-width: 1024px) {
.sidebar { width: 250px; }
}
/* 组件级:根据组件实际宽度调整内部布局 */
@container card (min-width: 400px) {
.card { grid-template-columns: 1fr 2fr; }
}
七、浏览器兼容性
| 浏览器 | 最低版本 |
|---|---|
| Chrome / Edge | 105+ |
| Firefox | 110+ |
| Safari | 16+ |
如需兼容旧浏览器,可用
@media做兜底,或用resizeObserver+ CSS 变量实现类似效果。
八、总结
@container= 查询容器宽度 → 组件级响应式@media= 查询屏幕宽度 → 页面级响应式- 两者互补 使用:
@media管页面框架,@container管组件细节 - 三步使用:声明容器 → 写查询规则 → 容器内放置元素