CSS Container Queries:彻底告别 @media 写到手软,附 5 个真实布局案例

以前写响应式组件,总要根据视口宽度写一堆 @media,代码又臭又长。现在 Container Queries 让组件根据父容器尺寸响应,代码直接减半。本文讲透语法 + 5 个可直接复用的案例。


一、Container Queries 解决了什么问题?

@media 媒体查询基于视口宽度。这导致一个组件在不同父容器下无法独立响应------同样的卡片,在侧边栏和主内容区需要两套样式或者额外类名。

Container Queries 允许你定义:当父容器达到某个宽度时,子元素改变布局。

css 复制代码
/* 以前:基于视口,无法区分卡片在哪个容器里 */
@media (min-width: 600px) {
  .card { display: flex; }
}

/* 现在:基于父容器宽度 */
@container (min-width: 300px) {
  .card { display: flex; }
}

二、基础语法(三步搞定)

2.1 定义容器

css 复制代码
.sidebar {
  container-type: inline-size;   /* 监听内联方向(宽度)变化 */
  container-name: sidebar;       /* 可选,给容器起名 */
}
  • container-type: inline-size 最常用,表示根据宽度变化。
  • 也可以 size(宽高都监听)或 normal(不监听)。

2.2 使用 @container

css 复制代码
@container (min-width: 300px) {
  .card-title {
    font-size: 1.5rem;
  }
}

如果只有一个容器,可以直接写条件。如果有多个容器,用 container-name 限定:

css 复制代码
@container sidebar (min-width: 300px) {
  /* 只对 sidebar 容器内的元素生效 */
}

2.3 组合与范围

css 复制代码
@container (100px <= width < 300px) {
  /* 容器宽度在 100px 到 300px 之间 */
}

三、与 @media 对比(代码量减少 50%)

场景 传统 @media 做法 Container Queries 做法
卡片在侧边栏时垂直,在主区域时水平 写两套类名或全局判断 父容器定义后,卡片内一套规则自动适配
仪表盘小部件适应不同格子尺寸 根据视口断点统一控制 每个小部件独立响应自己的容器

代码对比

html 复制代码
<!-- 以前:需要额外类名 -->
<div class="sidebar">
  <div class="card vertical"></div>
</div>
<div class="main">
  <div class="card horizontal"></div>
</div>
css 复制代码
/* 以前:手动控制 */
.card.vertical { flex-direction: column; }
.card.horizontal { flex-direction: row; }

/* Container Queries:一套规则 */
.card {
  container-type: inline-size;
}
@container (min-width: 400px) {
  .card { flex-direction: row; }
}
@container (max-width: 399px) {
  .card { flex-direction: column; }
}

四、5 个实战案例(可直接复制)

案例 1:卡片组件根据容器宽度切换布局

html 复制代码
<div class="card-container">
  <div class="card">
    <img src="photo.jpg" alt="">
    <div class="card-body">
      <h3>标题</h3>
      <p>描述文字</p>
    </div>
  </div>
</div>
css 复制代码
.card-container {
  container-type: inline-size;
}
.card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
@container (min-width: 350px) {
  .card {
    flex-direction: row;
    align-items: center;
  }
  .card img {
    width: 40%;
  }
}

案例 2:侧边栏与主内容区共享同一卡片组件

css 复制代码
/* 不需要任何额外代码,卡片自己响应父容器宽度 */
.sidebar { container-type: inline-size; width: 280px; }
.main { container-type: inline-size; width: 800px; }
/* 卡片规则如上,当父容器<350px时垂直,>350px时水平 */

案例 3:仪表盘小部件矩阵

html 复制代码
<div class="dashboard">
  <div class="widget" style="width: 200px">...</div>
  <div class="widget" style="width: 400px">...</div>
  <div class="widget" style="width: 200px">...</div>
</div>
css 复制代码
.widget {
  container-type: inline-size;
}
.widget-content {
  font-size: 12px;
}
@container (min-width: 250px) {
  .widget-content {
    font-size: 16px;
    display: flex;
    gap: 1rem;
  }
}

案例 4:商品列表切换行列(类似 Grid 与 Flex 混合)

css 复制代码
.product-list {
  container-type: inline-size;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}
.product-item {
  flex: 1 1 200px;
}
@container (max-width: 500px) {
  .product-item {
    flex-basis: 100%;  /* 小于500px时每行一个 */
  }
}

案例 5:自适应导航栏(折叠菜单)

html 复制代码
<nav class="navbar">
  <div class="logo">Logo</div>
  <ul class="nav-links">
    <li>首页</li>
    <li>产品</li>
    <li>关于</li>
  </ul>
</nav>
css 复制代码
.navbar {
  container-type: inline-size;
  display: flex;
  justify-content: space-between;
}
.nav-links {
  display: flex;
  gap: 1rem;
}
@container (max-width: 500px) {
  .navbar {
    flex-direction: column;
  }
  .nav-links {
    flex-direction: column;
    margin-top: 0.5rem;
  }
}

五、浏览器兼容性与降级方案

支持情况(截至 2026-06):

  • Chrome 105+ ✅
  • Firefox 110+ ✅
  • Safari 16+ ✅
  • Edge 105+ ✅

如果需要兼容旧浏览器 ,使用 @supports 渐进增强:

css 复制代码
/* 降级:默认样式(例如始终垂直) */
.card {
  flex-direction: column;
}
/* 支持 Container Queries 时覆盖 */
@supports (container-type: inline-size) {
  .card-container {
    container-type: inline-size;
  }
  @container (min-width: 350px) {
    .card {
      flex-direction: row;
    }
  }
}

六、总结

  • Container Queries 让组件根据父容器而非视口响应,实现真正的组件级响应式。
  • 语法简单:container-type + @container
  • 5 个案例覆盖卡片、侧边栏、仪表盘、商品列表、导航栏。
  • 兼容性已可投入生产,配合 @supports 安全降级。

文中所有代码均可直接复制到项目中。以后写响应式组件,先问自己:这个样式是由视口决定,还是由父容器决定?

讨论 :你在开发中遇到过哪些因 @media 全局断点导致的组件复用困难?欢迎留言分享。

相关推荐
小小小小宇2 小时前
OpenMemory MCP
前端
和平宇宙3 小时前
AI笔记005. hermes-DeepSeek V4 Pro, 128K上下文引发的探索
前端·人工智能·笔记
IT_陈寒3 小时前
Redis持久化这个坑,我爬了一整天才出来
前端·人工智能·后端
naildingding3 小时前
3-ts接口 Interface
前端·typescript
mONESY3 小时前
JavaScript 栈、队列、数组与链表核心知识点总结
javascript·面试
贺国亚3 小时前
电商AI辅助交易场景
面试
小小前端仔LC4 小时前
Node.js + LangChain + React:搭建个人知识库(六)- “吃什么”项目实战:从700+菜谱入库到Taro H5端JSON渲染
前端·后端
chase_my_dream4 小时前
C++ + SLAM 高频面试问题整理
开发语言·c++·面试
晓13134 小时前
【Cocos Creator 3.x】篇——第二章 入门
前端·javascript·游戏引擎