CSS教程

CSS容器查询@container

CSS容器查询@container:基于容器尺寸的响应式

本文由找找网为您提供,将详细介绍CSS容器查询(Container Queries)的概念、原理和实际应用,帮助您掌握这一现代化的响应式设计技术。

容器查询概述

CSS容器查询是近年来CSS领域最重要的新特性之一,它允许开发者根据父容器(而非视口)的尺寸来设置子元素的样式。与传统媒体查询基于视口尺寸不同,容器查询实现了真正组件级的响应式设计。

在传统的响应式设计中,我们使用媒体查询根据视口尺寸调整布局和样式。然而,在实际组件化开发中,组件可能被嵌入到页面的不同位置,其可用空间并不总是与视口尺寸直接相关。容器查询解决了这一痛点,让组件能够根据自身所在容器的尺寸自适应调整。

容器查询基本原理

容器查询与媒体查询的区别

容器查询与媒体查询的核心区别在于作用对象不同:

特性媒体查询 (@media)容器查询 (@container)
查询对象视口(viewport)尺寸特定容器元素尺寸
作用范围全局局部(仅影响容器后代)
组件适应性依赖视口断点依赖容器尺寸
复用性受全局布局影响高度可复用

容器查询工作机制

实现容器查询需要两个关键步骤:

  1. 将父元素声明为容器:使用 container-type 属性指定容器类型
  2. 基于容器尺寸设置样式:使用 @container 规则定义条件样式

容器查询遵循”最近容器优先原则”,即元素会优先监听最近一层具有 container-type 的父容器。

容器查询使用方法

定义容器上下文

要使元素成为查询容器,需要设置 container-type 属性:

  • inline-size:监听容器的行内方向尺寸(通常指宽度)
  • block-size:监听容器的块方向尺寸(通常指高度)
  • size:同时监听宽度和高度
  • style:允许查询自定义属性值
.card-container {
  container-type: inline-size;
  width: 100%;
  max-width: 800px;
  margin: 0 auto;
}

基本容器查询语法

定义容器后,可以使用 @container 规则根据容器尺寸应用样式:

@container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
  }

  .card-image {
    height: 200px;
  }
}

命名容器

当页面中有多个容器时,可以通过 container-name 属性为容器命名,避免查询冲突:

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

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

@container sidebar (max-width: 300px) {
  .navigation {
    display: none;
  }
}

@container main (min-width: 600px) {
  .article {
    font-size: 1.1rem;
    line-height: 1.6;
  }
}

容器查询的简写语法

可以使用 container 属性同时定义容器名称和类型:

.widget {
  container: widget / inline-size;
}

这等价于:

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

容器查询实战示例

示例1:自适应卡片组件

下面是一个完整的使用容器查询的自适应卡片组件示例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>容器查询示例 - 自适应卡片</title>
  <style>
    .card-container {
      container-type: inline-size;
      container-name: card-container;
      width: 100%;
      max-width: 1000px;
      margin: 0 auto;
      padding: 20px;
    }

    .card {
      background: #fff;
      border-radius: 8px;
      box-shadow: 0 2px 10px rgba(0,0,0,0.1);
      padding: 20px;
      transition: all 0.3s ease;
    }

    .card-header {
      margin-bottom: 15px;
    }

    .card-title {
      font-size: 1.25rem;
      margin: 0 0 10px 0;
      color: #333;
    }

    .card-image {
      width: 100%;
      height: 150px;
      background: #f0f0f0;
      border-radius: 4px;
      margin-bottom: 15px;
      object-fit: cover;
    }

    .card-content {
      color: #666;
      line-height: 1.5;
    }

    /* 窄容器样式(宽度 < 500px) */
    @container card-container (max-width: 499px) {
      .card {
        padding: 15px;
      }

      .card-title {
        font-size: 1.1rem;
      }
    }

    /* 中等容器样式(500px ≤ 宽度 < 700px) */
    @container card-container (min-width: 500px) and (max-width: 699px) {
      .card {
        display: flex;
        gap: 20px;
        align-items: flex-start;
      }

      .card-image {
        width: 120px;
        height: 120px;
        margin-bottom: 0;
        flex-shrink: 0;
      }
    }

    /* 宽容器样式(宽度 ≥ 700px) */
    @container card-container (min-width: 700px) {
      .card {
        display: grid;
        grid-template-columns: 200px 1fr;
        grid-template-rows: auto 1fr;
        gap: 20px;
      }

      .card-image {
        grid-row: 1 / -1;
        height: 200px;
        margin-bottom: 0;
      }

      .card-header {
        margin-bottom: 0;
      }
    }
  </style>
</head>
<body>
  <div class="card-container">
    <div class="card">
      <div class="card-image"></div>
      <div class="card-header">
        <h2 class="card-title">容器查询示例卡片</h2>
      </div>
      <div class="card-content">
        <p>此卡片会根据其容器的尺寸自动调整布局。尝试调整浏览器窗口大小,观察卡片布局的变化。</p>
        <p>在窄容器中,卡片采用单列布局;在中等宽度容器中,卡片采用水平布局;在宽容器中,卡片采用网格布局。</p>
      </div>
    </div>
  </div>
</body>
</html>

示例2:多列网格布局

下面的示例展示如何使用容器查询创建自适应的网格布局:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>容器查询示例 - 自适应网格</title>
  <style>
    .grid-container {
      container-type: inline-size;
      container-name: grid-container;
      width: 100%;
      max-width: 1200px;
      margin: 0 auto;
      padding: 20px;
    }

    .grid {
      display: grid;
      gap: 20px;
    }

    .grid-item {
      background: #fff;
      border-radius: 8px;
      box-shadow: 0 2px 10px rgba(0,0,0,0.1);
      padding: 20px;
      min-height: 100px;
    }

    /* 窄容器:单列布局 */
    @container grid-container (max-width: 499px) {
      .grid {
        grid-template-columns: 1fr;
      }
    }

    /* 中等容器:双列布局 */
    @container grid-container (min-width: 500px) and (max-width: 799px) {
      .grid {
        grid-template-columns: repeat(2, 1fr);
      }
    }

    /* 宽容器:三列布局 */
    @container grid-container (min-width: 800px) {
      .grid {
        grid-template-columns: repeat(3, 1fr);
      }
    }

    /* 超宽容器:四列布局 */
    @container grid-container (min-width: 1000px) {
      .grid {
        grid-template-columns: repeat(4, 1fr);
      }
    }
  </style>
</head>
<body>
  <div class="grid-container">
    <div class="grid">
      <div class="grid-item">项目 1</div>
      <div class="grid-item">项目 2</div>
      <div class="grid-item">项目 3</div>
      <div class="grid-item">项目 4</div>
      <div class="grid-item">项目 5</div>
      <div class="grid-item">项目 6</div>
    </div>
  </div>
</body>
</html>

容器查询单位

CSS为容器查询引入了一套新的相对单位,这些单位相对于查询容器的尺寸:

单位描述等效计算
cqw容器宽度的1%1cqw = 1% × 容器宽度
cqh容器高度的1%1cqh = 1% × 容器高度
cqi容器行内尺寸的1%横向排版中 = 容器宽度1%
cqb容器块级尺寸的1%横向排版中 = 容器高度1%
cqmincqicqb 中的较小值min(1cqi, 1cqb)
cqmaxcqicqb 中的较大值max(1cqi, 1cqb)

容器查询单位示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>容器查询单位示例</title>
  <style>
    .container {
      container-type: inline-size;
      container-name: demo-container;
      width: 80%;
      max-width: 800px;
      margin: 0 auto;
      padding: 20px;
      border: 1px solid #ddd;
    }

    .demo-box {
      background: #4CAF50;
      color: white;
      padding: 20px;
      text-align: center;
      margin-bottom: 20px;
    }

    /* 使用容器查询单位 */
    @container demo-container (min-width: 400px) {
      .demo-box {
        width: 50cqi; /* 容器宽度的50% */
        font-size: 2cqw; /* 字体大小随容器宽度变化 */
        margin: 0 auto 20px;
      }
    }

    @container demo-container (max-width: 399px) {
      .demo-box {
        width: 80cqi; /* 容器宽度的80% */
        font-size: 4cqw; /* 字体大小随容器宽度变化 */
        margin: 0 auto 20px;
      }
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="demo-box">
      此元素的尺寸和字体大小使用容器查询单位(cqi, cqw),会随容器尺寸变化。
    </div>
    <p>尝试调整浏览器窗口大小,观察上方盒子尺寸和字体大小的变化。</p>
  </div>
</body>
</html>

容器查询的高级用法

高度查询

除了宽度查询,容器查询也支持基于高度的条件:

.container {
  container-type: size;
  height: 400px;
  overflow: auto;
}

@container (min-height: 300px) {
  .content {
    display: flex;
    flex-direction: column;
  }

  .footer {
    margin-top: auto;
  }
}

容器滚动状态查询

CSS容器查询还支持检测滚动状态,这在某些交互场景中非常有用:

.scroll-container {
  container-type: scroll-state;
  height: 300px;
  overflow: auto;
}

@container scroll-state(scrollable: bottom) {
  .scroll-indicator {
    opacity: 0;
  }
}

样式查询

除了尺寸查询,容器查询还支持样式查询,可以查询容器的CSS属性值:

.theme-container {
  container-type: style;
  --theme: dark;
}

@container style(--theme: dark) {
  .component {
    background-color: #333;
    color: white;
  }
}

浏览器兼容性与降级方案

浏览器支持情况

截至2025年,主流浏览器对容器查询的支持率已超过90%。但对于不支持容器查询的浏览器,需要提供适当的降级方案。

特性检测与渐进增强

可以使用@supports规则检测浏览器是否支持容器查询,并提供降级样式:

.card {
  /* 默认样式,适用于不支持容器查询的浏览器 */
  display: block;
  padding: 10px;
}

@supports (container-type: inline-size) {
  .card-container {
    container-type: inline-size;
  }

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

最佳实践与性能考量

容器查询最佳实践

  1. 合理选择容器类型:大多数情况下使用 inline-size 即可满足需求,避免不必要的性能开销
  2. 有意义的断点:根据内容实际需求设置断点,而非随意数值
  3. 容器命名规范:为重要容器赋予有意义的名称,提高代码可维护性
  4. 避免过度使用:容器查询相比媒体查询有额外的性能开销,应避免过度使用
  5. 结合现代布局技术:将容器查询与CSS Grid和Flexbox结合使用

性能优化建议

  • 避免在单个页面上创建过多容器查询上下文
  • 优先使用 inline-size 而非 size,除非确实需要监听高度变化
  • 对于频繁变动的容器,考虑配合 contain: size 限定渲染区域

总结

容器查询知识点总结

知识点内容描述
基本概念容器查询允许根据父容器尺寸(而非视口)设置子元素样式
核心属性container-type 定义容器类型,container-name 为容器命名
查询语法使用 @container 规则根据容器尺寸应用条件样式
容器类型inline-size(宽度)、block-size(高度)、size(宽高)、style(样式)
相对单位cqwcqhcqicqbcqmincqmax 等容器查询单位
优势组件级响应式、更好的封装性、更高的可复用性
兼容性现代浏览器广泛支持,可使用 @supports 进行特性检测和降级

容器查询标志着CSS响应式设计进入了新的阶段,为组件化开发提供了更强大的工具。通过掌握容器查询,开发者可以创建出更加灵活、可维护的响应式组件,提升用户体验和开发效率。