CSS container queries:取代很多 media query 场景

起因

老办法做 responsive:

.card { padding: 1rem; }

@media (min-width: 768px) {
    .card { padding: 2rem; display: flex; }
}

依据viewport 调整。
但很多组件不关心 viewport,它关心自己父容器多大

例:card 组件放 sidebar(300px)时纵向布局,放主区(800px)时横向。
media query 帮不上忙 → 同 viewport 不同位置要不同样式。

Container queries(CSS 2023+ 主流支持)解决:组件根据容器
自己大小
调样式。

基本用法

父元素声明 containment:

.sidebar {
    container-type: inline-size;
    container-name: sidebar;
}

.main {
    container-type: inline-size;
}

子元素 query 容器:

.card {
    padding: 1rem;
    display: block;
}

@container (min-width: 500px) {
    .card {
        padding: 2rem;
        display: flex;
        gap: 1rem;
    }
}

card 在 sidebar (300px) 内 → block。
同 card 在 main (800px) 内 → flex。

containment type

  • inline-size:监听宽(最常用)
  • size:宽 + 高
  • normal:不监听(默认)
.parent { container-type: inline-size; }

注意:container-type 让元素成为 containment context,影响 layout
计算(不一定能在所有元素用)。

named container

.sidebar { container-type: inline-size; container-name: sidebar; }
.main { container-type: inline-size; container-name: main; }

@container sidebar (min-width: 400px) { ... }
@container main (max-width: 600px) { ... }

按 container 名 query,避免 ambiguity。

query unit (cqw / cqh)

.card {
    font-size: 5cqi;     /* container inline-size 的 5% */
    padding: 2cqi;
}
  • cqi:container inline-size 1%
  • cqb:container block-size 1%
  • cqw / cqh:absolute width/height (less common)

字号跟容器大小成正比,缩放友好。

实战 example:可复用 card

.card {
    container-type: inline-size;
    border: 1px solid #ddd;
    border-radius: 8px;
}

.card-inner {
    padding: 1rem;
}

.card-thumb {
    width: 100%;
    aspect-ratio: 16/9;
}

@container (min-width: 400px) {
    .card-inner {
        display: grid;
        grid-template-columns: 150px 1fr;
        gap: 1rem;
    }
    .card-thumb {
        width: 150px;
        aspect-ratio: 1;
    }
}

@container (min-width: 700px) {
    .card-inner {
        grid-template-columns: 200px 1fr;
    }
    .card-thumb {
        width: 200px;
    }
}

同一个 .card 在任何容器里自适应,不需要 media query 协调。

media query 仍有用

container query 不是 100% 替代 media query:

  • 页面级布局(sidebar/main 切换)→ media query
  • 组件内适应 → container query
  • 基于设备特性(hover / touch) → media query
  • prefers-color-scheme → media query

混用:

@media (prefers-color-scheme: dark) {
    .card { background: #222; }
}

@container (min-width: 500px) {
    .card { display: flex; }
}

style query (实验)

@container style(--theme: dark) {
    .card { background: black; }
}

依据自定义 prop 值变样式。Chrome 111+,Safari 18+。
还在 stabilizing。

浏览器支持

Chrome 105+ / Safari 16+ / Firefox 110+ → 主流浏览器从 2022 末 / 2023
全支持。

2026 视角:可以默认用,老 browser 用 @supports fallback:

@supports not (container-type: inline-size) {
    /* fallback to media query */
}

与 CSS-in-JS 对比

CSS-in-JS(styled-components / Emotion)经常通过 prop 控制样式:

<Card variant={width > 500 ? 'wide' : 'narrow'} />

JS 测宽 → re-render → 改样式。复杂 + JS 阻塞。

container query 纯 CSS,浏览器原生计算 → 更高效 + 简洁。

实际项目效果

我重构一个 dashboard,从 media query / JS measure 改 container query:

  • 删 200+ 行 JS layout logic
  • CSS 简化(不需要 at-768, at-1024 等命名)
  • 同组件在 modal / sidebar / 主区 都能 work
  • bundle 小 5KB

最大改善:组件真正可复用 —— 不需要为不同上下文写变体。

与 grid auto-fit / minmax 对比

/* grid 自适应 N 列 */
.grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

grid auto-fit 已经覆盖一些 container query 用例。
但 grid 是 layout 内自适应;container query 是组件内部样式。

踩过的坑

  1. container-type: inline-size 副作用:让元素 layout 隔离,
    某些 height 计算变化。布局突变 → 检查父子。

  2. 嵌套 container:子 container 的 query 默认查最近的 named
    container,不指定容易混乱。明确 container-name

  3. inline element 不能 container-type:必须 block / inline-block 或者
    display 至少能 contain。

  4. @container 在 nested rule 内:CSS nesting 里写时注意顺序。

  5. devtool 难调:Chrome devtools 显示 container query 没 media
    query 那么直观。仔细看 box model。

精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。