使用 CSS 容器查询的现代布局
构建响应容器而非视口的组件——@container、cqi 单位与实用模式。
CSS 容器查询是近年来添加到 Web 平台最重要的布局能力之一。与响应视口尺寸的媒体查询不同,容器查询使组件能根据其父容器尺寸自适应。这种从页面级到组件级响应式的转变解决了设计系统中的长期难题:构建在任何上下文中都看起来正确的真正可复用组件,而无需全局断点覆盖。
容器查询与媒体查询
媒体查询通过允许样式根据视口宽度变化革新了响应式设计。但视口宽度是单个组件可用空间的拙劣代理。侧边栏小部件、仪表板卡片和全宽主图区在视口相同时存在于不同宽度。
这种不匹配迫使开发者采用尴尬变通:
- 从父组件传递断点 props 以覆盖子样式。
- 使用 JavaScript ResizeObserver 根据元素宽度切换类。
- 为不同布局上下文创建重复组件变体。
- 依赖在布局变化时失效的 CSS grid 和 flexbox 技巧。
容器查询消除这些变通。包裹在容器上下文中的组件在其分配空间变化时自动调整内部布局 — 无论是视口调整、侧边栏切换还是网格列重排。
@container 规则
容器查询使用两个 CSS 构造:父元素上的 container-type 属性和后代样式上的 @container at 规则。父级声明自己为查询容器,子级根据容器尺寸编写条件样式。
/* Parent establishes a query container */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1rem;
}
/* Each card container enables size queries for its children */
.product-card {
container-type: inline-size;
container-name: card;
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
overflow: hidden;
}
/* Child styles respond to container width, not viewport */
@container card (min-width: 400px) {
.product-card .card-body {
display: flex;
gap: 1rem;
}
.product-card .card-image {
width: 40%;
flex-shrink: 0;
}
.product-card .card-details {
flex: 1;
}
}
@container card (max-width: 399px) {
.product-card .card-image {
width: 100%;
aspect-ratio: 16 / 9;
}
}
container-type 属性接受 inline-size(水平书写模式下的宽度)、size(宽高)或 normal(非容器)。大多数布局用例只需 inline-size,也是最高效的选项,因为浏览器只跟踪一个维度。
容器查询单位
容器查询引入了引用查询容器尺寸而非视口的新 CSS 长度单位。这些单位实现随组件尺寸缩放的流体排版和间距。
- cqw — 查询容器宽度的 1%。
- cqh — 查询容器高度的 1%。
- cqi — 查询容器行内尺寸的 1%。
- cqb — 查询容器块尺寸的 1%。
- cqmin — cqi 和 cqb 中较小者。
- cqmax — cqi 和 cqb 中较大者。
.stat-widget {
container-type: inline-size;
}
.stat-widget .value {
/* Font size scales with container width */
font-size: clamp(1.5rem, 5cqi, 3rem);
}
.stat-widget .label {
font-size: clamp(0.75rem, 2.5cqi, 1rem);
}
将容器查询单位与 clamp() 结合,在组件内创建平滑缩放的排版,无需硬断点跳跃。窄侧边栏中的统计小部件渲染较小文字,宽仪表板面板中的同一组件渲染较大文字 — 自动完成,无需 props 或 JavaScript。
样式查询与容器查询特性
除尺寸查询外,CSS 容器查询规范还包括响应容器计算样式值的样式查询。你可查询自定义属性值,使组件感知父级主题上下文。
.theme-container {
container-type: inline-size;
--variant: default;
}
.theme-container[data-variant="compact"] {
--variant: compact;
}
@container style(--variant: compact) {
.nested-component {
padding: 0.5rem;
font-size: 0.875rem;
}
}
样式查询在设计系统中特别强大:容器设置语义令牌,子组件相应调整密度、间距和排版。此模式取代通过组件树钻取变体标志。
无需媒体查询构建响应式组件
容器查询的实用目标是组件在任何放置处都正确工作。考虑用于全页视图、模态对话框和仪表板小部件的数据表组件。仅使用媒体查询时,三个实例共享绑定视口宽度的相同断点逻辑,至少在一个上下文中产生破损布局。
使用容器查询,表格组件定义自己的响应式行为:
- 容器宽度超过 600px — 以标准表格布局显示所有列。
- 400px 至 600px — 隐藏低优先级列,减少内边距。
- 低于 400px — 切换到带标签-值对的堆叠卡片布局。
.data-table-wrapper {
container-type: inline-size;
container-name: table;
overflow-x: auto;
}
@container table (max-width: 399px) {
.data-table thead {
display: none;
}
.data-table tr {
display: block;
margin-bottom: 1rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
padding: 0.75rem;
}
.data-table td {
display: flex;
justify-content: space-between;
padding: 0.25rem 0;
}
.data-table td::before {
content: attr(data-label);
font-weight: 600;
}
}
此组件对其父布局零知识。放入任何容器即可自适应。这就是容器查询兑现的承诺。
框架集成
现代 CSS 框架原生拥抱容器查询。Tailwind CSS v4 包含容器查询变体 — 在断点前加 @ 前缀即可根据容器尺寸应用样式。Styled-components 等 CSS-in-JS 库在模板字面量中支持 @container at 规则,无需额外配置。
在 React 组件库中,在组件根建立容器上下文,让内部元素使用容器查询做布局决策。记录哪些组件具有容器感知,以便消费者知道避免将其约束在最小功能宽度以下。
浏览器支持与渐进增强
截至 2026 年,容器查询在 Chrome、Firefox、Safari 和 Edge 中获得广泛支持。对于少数不支持的传统浏览器,应用渐进增强:为最常见容器尺寸设计默认样式,再为支持的浏览器添加容器查询覆盖。
使用 @supports 规则检测容器查询支持,必要时提供媒体查询回退:
/* Fallback for browsers without container query support */
@media (max-width: 600px) {
.product-card .card-body {
flex-direction: column;
}
}
/* Enhanced layout for supporting browsers */
@supports (container-type: inline-size) {
@container card (max-width: 399px) {
.product-card .card-body {
flex-direction: column;
}
}
}
容器查询标志着 CSS 作为组件驱动设计语言的成熟。通过将响应式逻辑从页面级转移到组件级,它们使设计系统中每个组件真正自包含、自适应且可复用。在下一个项目中拥抱容器查询,体验响应式设计本应如此工作的方式。