CSS 容器查询

介绍

CSS 容器查询是 CSS 中一项革命性的新特性,它允许开发者根据父容器的大小而非视口大小来调整元素的样式。这意味着组件现在可以根据它们在布局中的位置和可用空间自动调整自身样式,而不仅仅是根据屏幕尺寸。在本章中,我们将探讨容器查询的工作原理、使用方法以及它们如何改变我们构建响应式组件的方式。

核心知识点

容器查询基础

1. 容器类型

  • container-type:定义容器的类型,决定容器如何测量其大小
  • size:同时考虑容器的宽度和高度
  • inline-size:只考虑容器的内联方向大小(通常是宽度)
  • block-size:只考虑容器的块方向大小(通常是高度)

2. 容器名称

  • container-name:为容器指定一个名称,允许更具针对性的查询
  • 容器名称可以是任意有效的标识符
  • 多个容器可以共享同一个名称

3. 容器查询语法

  • @container:定义一个容器查询
  • 查询条件:使用与媒体查询类似的语法
  • 可以基于容器的宽度、高度、方向等进行查询

容器查询高级特性

1. 容器查询单位

  • cqw:容器查询宽度单位(容器宽度的 1%)
  • cqh:容器查询高度单位(容器高度的 1%)
  • cqi:容器查询内联尺寸单位(容器内联尺寸的 1%)
  • cqb:容器查询块尺寸单位(容器块尺寸的 1%)
  • cqmin:容器查询最小单位(容器最小维度的 1%)
  • cqmax:容器查询最大单位(容器最大维度的 1%)

2. 容器查询逻辑

  • 可以使用 andornot 逻辑操作符组合多个条件
  • 可以嵌套容器查询
  • 可以结合媒体查询使用

3. 容器查询优先级

  • 容器查询的优先级与常规 CSS 规则相同
  • 更具体的选择器仍然具有更高的优先级
  • 容器查询不会改变选择器的特异性

实用示例

示例 1:基本容器查询

/* 定义容器 */
.card-container {
  container-type: inline-size;
  container-name: card;
  width: 300px;
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 16px;
}

/* 基本容器查询 */
@container card (min-width: 400px) {
  .card-content {
    display: flex;
    gap: 20px;
  }
  
  .card-image {
    flex-shrink: 0;
    width: 120px;
    height: 120px;
  }
  
  .card-text {
    flex: 1;
  }
}

/* 更大容器的样式 */
@container card (min-width: 600px) {
  .card {
    padding: 24px;
  }
  
  .card-title {
    font-size: 1.5rem;
  }
  
  .card-image {
    width: 160px;
    height: 160px;
  }
}

示例 2:使用容器查询单位

/* 定义容器 */
.text-container {
  container-type: inline-size;
  container-name: text;
}

/* 使用容器查询单位 */
@container text {
  .responsive-text {
    font-size: clamp(1rem, 5cqw, 2rem);
    line-height: 1.4;
  }
  
  .text-heading {
    font-size: clamp(1.5rem, 8cqw, 3rem);
    margin-bottom: 0.5em;
  }
  
  .text-padding {
    padding: clamp(1rem, 4cqw, 2rem);
  }
}

示例 3:嵌套容器查询

/* 外层容器 */
.grid-container {
  container-type: inline-size;
  container-name: grid;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
}

/* 内层容器 */
.card {
  container-type: inline-size;
  container-name: card;
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 16px;
}

/* 外层容器查询 */
@container grid (min-width: 800px) {
  .grid-container {
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  }
}

/* 内层容器查询 */
@container card (min-width: 300px) {
  .card-content {
    display: flex;
    gap: 16px;
  }
  
  .card-image {
    flex-shrink: 0;
    width: 100px;
    height: 100px;
  }
}

示例 4:响应式导航组件

/* 导航容器 */
.nav-container {
  container-type: inline-size;
  container-name: nav;
  background-color: #333;
  color: white;
  padding: 10px;
}

/* 基础导航样式 */
.nav {
  list-style: none;
  padding: 0;
  margin: 0;
}

.nav-item {
  margin-bottom: 10px;
}

.nav-link {
  color: white;
  text-decoration: none;
  display: block;
  padding: 8px 12px;
  border-radius: 4px;
}

.nav-link:hover {
  background-color: rgba(255,255,255,0.1);
}

/* 容器查询 - 水平导航 */
@container nav (min-width: 400px) {
  .nav {
    display: flex;
    gap: 10px;
  }
  
  .nav-item {
    margin-bottom: 0;
  }
}

/* 容器查询 - 带徽标的导航 */
@container nav (min-width: 600px) {
  .nav-container {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  
  .nav-brand {
    font-weight: bold;
    font-size: 1.2rem;
  }
}

示例 5:响应式卡片网格

/* 卡片网格容器 */
.card-grid {
  container-type: inline-size;
  container-name: grid;
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

/* 卡片容器 */
.card {
  container-type: inline-size;
  container-name: card;
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
}

/* 卡片内容 */
.card-image {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

.card-content {
  padding: 16px;
}

/* 网格容器查询 */
@container grid (min-width: 600px) {
  .card-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@container grid (min-width: 900px) {
  .card-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* 卡片容器查询 */
@container card (min-width: 300px) {
  .card-content {
    padding: 20px;
  }
  
  .card-title {
    font-size: 1.2rem;
  }
}

@container card (min-width: 400px) {
  .card {
    display: flex;
    flex-direction: column;
    height: 100%;
  }
  
  .card-content {
    flex: 1;
    display: flex;
    flex-direction: column;
  }
  
  .card-button {
    margin-top: auto;
    align-self: flex-start;
  }
}

实践练习

练习 1:创建响应式卡片组件

创建一个响应式卡片组件,具有以下特点:

  • 当卡片宽度小于 300px 时,垂直布局(图片在上,内容在下)
  • 当卡片宽度大于等于 300px 时,水平布局(图片在左,内容在右)
  • 当卡片宽度大于等于 400px 时,增加内边距和字体大小
  • 使用容器查询单位调整字体大小和间距

练习 2:创建自适应导航菜单

创建一个自适应导航菜单,具有以下特点:

  • 当容器宽度小于 400px 时,显示为垂直菜单
  • 当容器宽度大于等于 400px 时,显示为水平菜单
  • 当容器宽度大于等于 600px 时,添加品牌标志并右对齐菜单
  • 当容器宽度大于等于 800px 时,增加菜单项间距

练习 3:创建响应式网格布局

创建一个响应式网格布局,具有以下特点:

  • 使用容器查询调整网格列数
  • 当容器宽度小于 600px 时,单列布局
  • 当容器宽度大于等于 600px 时,双列布局
  • 当容器宽度大于等于 900px 时,三列布局
  • 当容器宽度大于等于 1200px 时,四列布局
  • 每个网格项根据自身宽度调整内部布局

总结

在本章中,我们探讨了 CSS 容器查询,这是一项改变游戏规则的 CSS 特性,它允许组件根据其父容器的大小而非视口大小来调整自身样式。我们涵盖了:

  1. 容器查询的基础知识,包括容器类型和容器名称的定义
  2. 容器查询的语法和使用方法
  3. 容器查询单位,用于创建真正响应容器大小的布局
  4. 嵌套容器查询的高级用法
  5. 实际应用示例,如响应式导航和卡片网格

容器查询为组件化设计带来了新的可能性,使组件能够在不同的布局上下文中自动适应和调整。它们补充了媒体查询,提供了更细粒度的响应式控制,使我们能够创建更加灵活和可重用的组件。

复习问题

  1. 容器查询与媒体查询的主要区别是什么?
  2. 如何定义一个容器查询容器?
  3. 容器查询支持哪些容器类型?
  4. 什么是容器查询单位?它们如何工作?
  5. 如何嵌套容器查询?
  6. 容器查询可以用于哪些实际场景?
  7. 容器查询的浏览器支持情况如何?
  8. 如何使用容器查询创建响应式卡片组件?

进一步阅读

« 上一篇 CSS 高级特性 下一篇 » CSS 嵌套