CSS `Container Queries` (容器查询) (提案):基于容器尺寸的响应式设计

各位观众,晚上好!我是你们的老朋友,今天咱们聊聊 CSS 世界里冉冉升起的新星——Container Queries (容器查询)。这玩意儿啊,说白了,就是让组件自己说了算,看看自己住的“房子”有多大,再决定长成啥样。

响应式设计的痛点:视口查询的局限性

在传统的响应式设计中,我们主要依靠的是 Media Queries (媒体查询)。它根据 视口 (viewport,也就是浏览器窗口) 的尺寸来改变样式。这在很多情况下都很好用,但也有它的局限性。

想象一下:你有一个卡片组件,需要在不同的页面上使用。在大的页面上,它应该占据更大的空间,显示更详细的信息;在小的页面上,它应该更紧凑,只显示关键信息。问题来了:这个卡片组件的样式完全依赖于视口的宽度,而不是它 实际 占据的空间。

如果这个卡片组件在一个大的页面上,但被放在一个很窄的侧边栏里呢?它仍然会按照大屏幕的样式显示,导致内容溢出或者显示不美观。这就是视口查询的局限性:它只关心视口,不关心组件自己的容器。

<div class="container">
  <div class="card">
    <h1>文章标题</h1>
    <p>文章摘要...</p>
    <a href="#">阅读更多</a>
  </div>
</div>

<style>
.card {
  border: 1px solid #ccc;
  padding: 16px;
}

/* 媒体查询:基于视口宽度 */
@media (min-width: 768px) {
  .card {
    font-size: 1.2em; /* 在大屏幕上增大字体 */
  }
}
</style>

在这个例子中,.card 的字体大小只会在视口宽度大于 768px 时才会改变,即使 .card 实际上占据的空间非常小。

Container Queries:组件级别的响应式

Container Queries 正是为了解决这个问题而生的。它允许我们根据 容器 (container,也就是组件的父元素) 的尺寸来改变组件的样式,而不是依赖于视口。这使得组件可以真正地响应它所处的环境,更加灵活和可复用。

<div class="container">
  <div class="card">
    <h1>文章标题</h1>
    <p>文章摘要...</p>
    <a href="#">阅读更多</a>
  </div>
</div>

<style>
.container {
  container-type: inline-size; /* 定义容器类型 */
}

.card {
  border: 1px solid #ccc;
  padding: 16px;
}

/* 容器查询:基于容器宽度 */
@container (min-width: 400px) {
  .card {
    font-size: 1.2em; /* 在容器宽度大于 400px 时增大字体 */
  }
}
</style>

在这个例子中,我们首先使用 container-type: inline-size.container 定义为一个容器。然后,我们使用 @container 规则来定义容器查询。只有当 .container 的宽度大于 400px 时,.card 的字体大小才会改变。

核心概念:

  1. Container Context (容器上下文): 组件所处的容器。
  2. Container Name (容器名称): 可选,给容器起一个名字,方便在查询时引用。
  3. Container Type (容器类型): 定义容器的尺寸计算方式,常见类型有 sizeinline-size
  4. @container Rule (容器查询规则): 定义基于容器尺寸的样式规则。

Container Type:定义容器的尺寸

container-type 属性定义了容器的尺寸计算方式。它有几个可选值:

  • size: 容器的 块级尺寸 (block-size) 和 行内尺寸 (inline-size) 都作为查询条件。简单来说,就是高度和宽度都参与查询。
  • inline-size: 容器的 行内尺寸 (inline-size) 作为查询条件。通常指的是宽度,在水平书写模式下。
  • normal: 默认值,不创建容器上下文。
  • style: (实验性) 容器的样式作为查询条件,超出本讲座范围。

选择哪种 container-type 取决于你的需求。如果你只需要根据容器的宽度来改变样式,inline-size 就足够了。如果你需要根据容器的高度和宽度来改变样式,可以使用 size

/* 容器类型示例 */
.container-size {
  container-type: size; /* 高度和宽度都参与查询 */
}

.container-inline-size {
  container-type: inline-size; /* 只有宽度参与查询 */
}

Container Name:给容器起个好名字

container-name 属性允许你给容器起一个名字。这在复杂的布局中非常有用,可以避免混淆。

<div class="sidebar" container-name="sidebar-container" container-type="inline-size">
  <div class="card">
    <h1>文章标题</h1>
    <p>文章摘要...</p>
    <a href="#">阅读更多</a>
  </div>
</div>

<style>
/* 使用容器名称进行查询 */
@container sidebar-container (min-width: 300px) {
  .card {
    font-size: 1.1em;
  }
}
</style>

在这个例子中,我们给 .sidebar 容器起了个名字叫 sidebar-container。然后在 @container 规则中,我们使用 sidebar-container 来指定要查询的容器。

如果省略了 container-name,则 @container 规则会查找最近的 匿名 容器。

@container Rule:编写查询规则

@container 规则是 Container Queries 的核心。它的语法如下:

@container <container-name>? <condition> {
  /* 样式规则 */
}
  • <container-name>: 可选,容器的名称。
  • <condition>: 查询条件,比如 min-width, max-width, min-height, max-height 等。

常用的查询条件:

条件 描述
min-width 容器的最小宽度
max-width 容器的最大宽度
min-height 容器的最小高度
max-height 容器的最大高度
width > <value> 容器的宽度大于指定值
width < <value> 容器的宽度小于指定值
height > <value> 容器的高度大于指定值
height < <value> 容器的高度小于指定值

示例:

/* 容器宽度大于 500px */
@container (min-width: 500px) {
  .card {
    background-color: #f0f0f0;
  }
}

/* 容器高度小于 300px */
@container (max-height: 300px) {
  .card {
    padding: 8px;
  }
}

/* 容器宽度在 300px 到 600px 之间 */
@container (min-width: 300px) and (max-width: 600px) {
  .card {
    border-width: 2px;
  }
}

/* 容器高度大于 200px 并且宽度大于 400px */
@container (min-height: 200px) and (min-width: 400px) {
  .card {
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  }
}

实际应用场景

Container Queries 在很多场景下都非常有用。这里列举几个常见的例子:

  1. 卡片组件: 根据卡片容器的尺寸,调整卡片的内容布局、字体大小、图片大小等。
  2. 导航栏: 根据导航栏容器的尺寸,调整导航链接的排列方式、图标大小等。
  3. 侧边栏: 根据侧边栏容器的尺寸,调整侧边栏的宽度、内容显示方式等。
  4. 表单: 根据表单容器的尺寸,调整表单元素的布局、字体大小等。

案例 1:响应式卡片组件

<div class="container">
  <div class="card">
    <img src="image.jpg" alt="图片">
    <h2>文章标题</h2>
    <p>文章摘要...</p>
    <a href="#">阅读更多</a>
  </div>
</div>

<style>
.container {
  container-type: inline-size;
}

.card {
  border: 1px solid #ccc;
  padding: 16px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

img {
  width: 100%;
  max-width: 300px;
  margin-bottom: 16px;
}

/* 容器宽度小于 400px */
@container (max-width: 400px) {
  .card {
    align-items: flex-start;
  }

  img {
    max-width: 150px;
    margin-right: 16px;
    margin-bottom: 0;
    float: left;
  }

  h2 {
    font-size: 1.1em;
  }

  p {
    font-size: 0.9em;
  }
}
</style>

在这个例子中,当卡片容器的宽度小于 400px 时,图片会浮动到左侧,文字会环绕图片,卡片组件的布局会发生改变。

案例 2:响应式导航栏

<nav class="navbar">
  <a href="#">首页</a>
  <a href="#">产品</a>
  <a href="#">服务</a>
  <a href="#">关于</a>
  <a href="#">联系我们</a>
</nav>

<style>
.navbar {
  container-type: inline-size;
  display: flex;
  justify-content: space-around;
  padding: 16px;
  background-color: #f0f0f0;
}

.navbar a {
  text-decoration: none;
  color: #333;
  padding: 8px 16px;
}

/* 容器宽度小于 600px */
@container (max-width: 600px) {
  .navbar {
    flex-direction: column;
    align-items: center;
  }

  .navbar a {
    margin-bottom: 8px;
  }
}
</style>

在这个例子中,当导航栏容器的宽度小于 600px 时,导航链接会垂直排列,而不是水平排列。

与 Media Queries 的比较

特性 Media Queries Container Queries
响应对象 视口 (viewport) 容器 (container)
响应依据 视口的尺寸 (宽度、高度、设备类型等) 容器的尺寸 (宽度、高度)
适用场景 整体页面布局、全局样式 组件级别的响应式设计、局部样式
灵活性 相对较低,依赖全局视口状态 较高,组件可以独立响应其容器的状态
可复用性 较低,样式规则可能需要在不同页面重复定义 较高,组件可以根据其容器的尺寸自动调整样式

什么时候使用 Container Queries?

  • 当你想让组件根据其 实际 占据的空间来改变样式时。
  • 当你需要在不同的页面上复用同一个组件,并且希望它能够自动适应不同的布局时。
  • 当你需要更精细地控制组件的样式,使其更加灵活和可定制时。

什么时候使用 Media Queries?

  • 当你需要改变整体页面布局时。
  • 当你需要根据设备类型 (比如手机、平板、电脑) 来应用不同的样式时。
  • 当你需要全局性的样式调整时。

总结:Media Queries 适用于全局的、基于视口的响应式设计;Container Queries 适用于局部的、基于容器的响应式设计。两者可以结合使用,以实现更加灵活和强大的响应式效果。

浏览器兼容性

Container Queries 的浏览器兼容性正在逐步提高。目前,主流浏览器都已经支持了 Container Queries,但可能需要开启实验性功能。

  • Chrome: 从 Chrome 105 开始默认启用。
  • Firefox: 需要手动开启 layout.css.container-queries.enabled 标志。
  • Safari: 从 Safari 16 开始支持。
  • Edge: 基于 Chromium 内核,与 Chrome 保持一致。

在使用 Container Queries 时,建议使用渐进增强的方式,确保在不支持 Container Queries 的浏览器上也能提供良好的用户体验。

总结与展望

Container Queries 是 CSS 世界里的一项重要创新。它打破了视口查询的局限性,让组件可以真正地响应它所处的环境,更加灵活和可复用。虽然目前 Container Queries 的浏览器兼容性还在完善中,但相信随着时间的推移,它将会成为响应式设计的标配。

希望今天的讲座能够帮助大家更好地理解 Container Queries。记住,好的设计是能够适应变化的,而 Container Queries 正是帮助我们实现这一目标的重要工具。

下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注