CSS 容器查询完全指南

引言

CSS 容器查询(Container Queries)是 CSS 规范中的一项革命性特性,它允许开发者根据容器的尺寸而非视口尺寸来应用样式。本文将深入探讨容器查询的各种用法和高级技巧。

基础概念回顾

容器查询 vs 媒体查询

特性媒体查询容器查询
基于视口尺寸容器尺寸
语法@media@container
作用范围全局局部

基本语法

@container (min-width: 400px) {
  .card {
    flex-direction: row;
  }
}

高级技巧一:容器类型

size 容器

.container {
  container-type: size;
}

inline-size 容器

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

block-size 容器

.container {
  container-type: block-size;
}

高级技巧二:命名容器

定义命名容器

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

使用命名容器

@container card (min-width: 400px) {
  .card {
    flex-direction: row;
  }
}

组合使用

@container card (min-width: 400px) and (max-width: 600px) {
  .card {
    padding: 1.5rem;
  }
}

高级技巧三:容器查询单位

cqw - 容器查询宽度单位

@container (min-width: 400px) {
  .title {
    font-size: 5cqw;
  }
}

cqh - 容器查询高度单位

@container (min-height: 300px) {
  .content {
    font-size: 3cqh;
  }
}

cqi - 容器查询内联轴单位

@container (min-inline-size: 400px) {
  .item {
    width: 25cqi;
  }
}

cqb - 容器查询块轴单位

@container (min-block-size: 300px) {
  .item {
    height: 25cqb;
  }
}

cqmin 和 cqmax

@container (min-width: 400px) {
  .box {
    padding: cqmin(10px, 5%);
  }
}

高级技巧四:嵌套容器查询

基础嵌套

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

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

@container outer (min-width: 600px) {
  .card {
    background: blue;
  }
  
  @container inner (min-width: 300px) {
    .title {
      font-size: 1.5rem;
    }
  }
}

多层嵌套

.level-1 {
  container-type: inline-size;
  container-name: level1;
}

.level-2 {
  container-type: inline-size;
  container-name: level2;
}

.level-3 {
  container-type: inline-size;
  container-name: level3;
}

@container level1 (min-width: 800px) {
  @container level2 (min-width: 600px) {
    @container level3 (min-width: 400px) {
      .content {
        color: red;
      }
    }
  }
}

高级技巧五:容器查询与 Flexbox/Grid

响应式 Flexbox

.card-container {
  container-type: inline-size;
  container-name: cardContainer;
  display: flex;
  gap: 1rem;
}

@container cardContainer (max-width: 500px) {
  .card-container {
    flex-direction: column;
  }
}

响应式 Grid

.grid-container {
  container-type: inline-size;
  container-name: gridContainer;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}

@container gridContainer (max-width: 800px) {
  .grid-container {
    grid-template-columns: repeat(2, 1fr);
  }
}

@container gridContainer (max-width: 400px) {
  .grid-container {
    grid-template-columns: 1fr;
  }
}

实战案例:响应式卡片组件

.card {
  container-type: inline-size;
  container-name: card;
  padding: 1rem;
  border-radius: 8px;
  background: white;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.card-header {
  margin-bottom: 1rem;
}

.card-title {
  font-size: 1rem;
  font-weight: bold;
}

.card-content {
  font-size: 0.875rem;
  color: #666;
}

.card-actions {
  margin-top: 1rem;
  display: flex;
  gap: 0.5rem;
}

@container card (min-width: 300px) {
  .card {
    padding: 1.5rem;
  }
  
  .card-title {
    font-size: 1.25rem;
  }
  
  .card-content {
    font-size: 1rem;
  }
}

@container card (min-width: 400px) {
  .card {
    display: flex;
    gap: 1.5rem;
  }
  
  .card-header {
    flex-shrink: 0;
    width: 150px;
  }
  
  .card-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
  }
  
  .card-actions {
    justify-content: flex-end;
  }
}

实战案例:响应式导航栏

.navbar {
  container-type: inline-size;
  container-name: navbar;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem;
  background: #333;
  color: white;
}

.logo {
  font-size: 1.25rem;
  font-weight: bold;
}

.nav-links {
  display: none;
  gap: 1.5rem;
}

.nav-links a {
  color: white;
  text-decoration: none;
}

.mobile-menu {
  display: block;
  cursor: pointer;
}

@container navbar (min-width: 600px) {
  .nav-links {
    display: flex;
  }
  
  .mobile-menu {
    display: none;
  }
}

实战案例:响应式表单

.form-container {
  container-type: inline-size;
  container-name: formContainer;
  padding: 1rem;
}

.form-group {
  margin-bottom: 1rem;
}

.form-group label {
  display: block;
  margin-bottom: 0.5rem;
  font-weight: 500;
}

.form-group input,
.form-group textarea {
  width: 100%;
  padding: 0.75rem;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.form-actions {
  display: flex;
  gap: 0.5rem;
}

@container formContainer (min-width: 500px) {
  .form-row {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1rem;
  }
  
  .form-actions {
    justify-content: flex-end;
  }
}

@container formContainer (min-width: 700px) {
  .form-row {
    grid-template-columns: repeat(3, 1fr);
  }
}

常见问题与解决方案

Q1:浏览器兼容性如何?

A:现代浏览器都支持容器查询:

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

Q2:如何优雅降级?

A:使用 @supports 检测:

.card {
  padding: 1rem;
}

@supports (container-type: inline-size) {
  .card {
    container-type: inline-size;
  }
  
  @container (min-width: 400px) {
    .card {
      padding: 1.5rem;
    }
  }
}

Q3:容器查询与媒体查询冲突吗?

A:不冲突,可以结合使用:

@media (min-width: 1024px) {
  .container {
    display: flex;
    gap: 2rem;
  }
}

@container (min-width: 400px) {
  .card {
    flex-direction: row;
  }
}

最佳实践

1. 使用 inline-size 优先

/* 推荐 */
.container {
  container-type: inline-size;
}

/* 不推荐 */
.container {
  container-type: size;
}

2. 命名容器

/* 推荐 */
.card-container {
  container-type: inline-size;
  container-name: card;
}

@container card (min-width: 400px) {
  /* 样式 */
}

/* 不推荐 */
.card-container {
  container-type: inline-size;
}

@container (min-width: 400px) {
  /* 样式 */
}

3. 结合 CSS Grid

.grid {
  container-type: inline-size;
  container-name: grid;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}

@container grid (min-width: 600px) {
  .grid {
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  }
}

总结

CSS 容器查询是响应式设计的重大进步。通过本文的学习,你应该能够:

  1. 理解容器查询的概念和优势
  2. 使用不同类型的容器查询
  3. 应用容器查询单位
  4. 实现嵌套容器查询
  5. 构建响应式组件

掌握这些技巧,能够帮助你创建更加灵活和可复用的组件。

更多推荐