CSS Container Queries 容器查询入门教程

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:为什么样式不生效?

检查清单:

  1. 容器是否声明了 container-type

    css 复制代码
    /* ❌ 错误:直接写 @container,但没有声明容器 */
    /* ✅ 正确:先声明容器 */
    .card-wrapper {
      container: card / inline-size;
    }
  2. 容器名称是否匹配

    css 复制代码
    /* 声明时叫 card */
    container: card / inline-size;
    
    /* 查询时也要叫 card */
    @container card (min-width: 400px) { }
  3. CSS 属性是否用了全角字符

    css 复制代码
    /* ❌ 错误:全角连字符 */
    container‑type: inline‑size;
    
    /* ✅ 正确:ASCII 连字符 */
    container-type: inline-size;
  4. 浏览器是否支持?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 管组件细节
  • 三步使用:声明容器 → 写查询规则 → 容器内放置元素
相关推荐
带多刺的玫瑰1 小时前
Leecode#4刷题之寻找两个正序数组的中位数
java·前端·算法
qq_267612891 小时前
项目集、里程碑与迭代联动:Gitee项目管理如何支撑多团队规模化交付与进度风险治理
前端·gitee
赵广陆1 小时前
企业实战:Web服务端搭建
前端·langchain·langgraph
常宇佳1 小时前
vue3 实战系列之无法识别vue组件
前端·javascript·vue.js
掘金者阿豪1 小时前
Codex 怎么突然变慢了?一个需求跑几十分钟,我才发现它的工作方式已经变了
前端·后端
用户931456355661 小时前
从 3 秒到 300 毫秒:一次真实的前端首屏性能优化全记录
前端
whn19771 小时前
dm9安装初体验
前端
阿黎梨梨2 小时前
从零搞懂 JWT 登录鉴权:一张“电子通行证”的诞生记
前端
用户921080262862 小时前
ChatMessageList 消息列表组件:基于 BubbleList 搭建 AI 对话展示区
前端