在 polyfill 进行重大更新时,容器查询开始进入稳定版浏览器

Gerald Monaco
Gerald Monaco

可以使用容器查询了!

好消息 — 最受欢迎的开发者功能之一已开始在网络浏览器中推出!从 Chromium 105Safari 16 开始,您现在可以在这些浏览器中创建基于大小的容器查询并使用容器查询单位值。为了能够更轻松地使用基于大小的容器查询和 cq 单元,Chrome 的 Aurora 团队一直在努力更新 Container Query Polyfill,以支持更多浏览器和用例,让您可以放心地使用这一强大的功能。

什么是容器查询?

容器查询是一项 CSS 功能,可让您编写样式逻辑,以定位父元素的功能来为其子元素设置样式。您可以通过查询父级的尺寸来创建真正基于组件的自适应设计。与仅提供视口大小信息的媒体查询等相比,这些信息更加精细且实用。

ALT_TEXT_HERE

借助容器查询,您可以编写可重复使用的组件,这些组件的显示方式会因其在网页中的位置而异。这样一来,它们在不同页面和模板中的弹性和响应能力会大大增强。

使用容器查询

假设您有一些 HTML:

<!-- card parent -->
<div class=”card-parent”>
  <div class=”card>
     <!-- card contents -->
      …
  </div>
</div>

如需使用容器查询,您首先需要对要跟踪的父元素设置包含关系。为此,您可以设置 container-type 属性,也可以使用 container 简写形式同时设置容器类型和容器名称。

.card-parent {
  /* query the inline-direction size of this parent */
  container-type: inline-size;
}

现在,您可以使用 @container 规则根据最近的父项设置样式。对于上图所示的设计(其中卡片可能会从一列变为两列),请编写如下代码:

@container (min-width: 300px) {
  .card {
    /* styles to apply when the card container (.card-parent in this case) is >= 300px */
    /* I.e. shift from 1-column to 2-column layout: */
    grid-template-columns: 1fr 1fr;
  }
}

为了更加简洁明确,请为父元素容器指定一个名称:

.card-parent {
  container-type: inline-size;
  /* set name here, or write this in one line using the container shorthand */
  container-name: card-container;
}

然后,将之前的代码重写为:

@container card-container (min-width: 300px) {
  .card {
    grid-template-columns: 1fr 1fr;
  }
}

容器查询单元

为使容器查询更加实用,您还可以使用基于容器的单位值。下表显示了可能的容器单位值及其与容器大小的对应关系:

单位相对于
cqw查询容器宽度的 1%
cqh查询容器高度的 1%
cqi查询容器内嵌大小的 1%
cqb查询容器块大小的 1%
cqmincqi 或 cqb 中的较小值
cqmaxcqi 或 cqb 中的较大值

响应排版就是如何使用基于容器的单元的一个示例。基于视口的单位(例如 vhvbvwvi)可用于调整屏幕上任何元素的大小。

.card h2 {
  font-size: 15cqi;
}

此代码会将字号设为容器内嵌大小的 15%,这意味着随着内嵌大小(宽度)的增加,字号会变大,随着内嵌大小的缩小,字号会变小。如需进一步优化,请使用 clamp() 函数为排版设置最小和最大尺寸限制,并根据容器大小自适应调整其尺寸:

.card h2 {
  font-size: clamp(1.5rem, 15cqi, 3rem);
}

现在,标题绝不会大于 3rem 或小于 .5rem,但会占用容器内嵌大小的 15%。

此演示进一步改进了宽度较大的卡片,使其在 2 列视图中显示时尺寸范围更小。

容器查询 polyfill

由于容器查询是一项非常强大的功能,因此我们希望您能够轻松地将其纳入到您的项目中,并且了解浏览器支持对此至关重要。因此,我们一直在努力改进容器查询多填充。此 polyfill 在以下平台中获得了广泛支持:

  • Firefox 69 及更高版本
  • Chrome 79 及更高版本
  • Edge 79 及更高版本
  • Safari 13.4 及更高版本

压缩后的大小小于 9kb,并将 ResizeObserver 与 MutationObserver 结合使用,以支持稳定版浏览器中目前提供的完整 @container 查询语法:

  • 离散查询 (width: 300pxmin-width: 300px)。
  • 范围查询 (200px < width < 400pxwidth < 400px)。
  • 属性和关键帧中的容器相对长度单位 (cqwcqhcqicqbcqmincqmax)。

使用容器查询 polyfill

要使用 polyfill,请将以下脚本标记添加到文档的标头中:

<script type="module">
  if (!("container" in document.documentElement.style)) {
    import("https://unpkg.com/container-query-polyfill@^0.2.0");
  }
</script>

您可能还希望使用服务根据 User-Agent 有条件地提供 polyfill,或者将其自托管到您自己的源。

为提供最佳用户体验,建议您最初仅将 polyfill 用于非首屏内容,并使用 @supports 查询暂时将其替换为加载指示器,直到 polyfill 准备好显示它为止:

@supports not (container-type: inline-size) {
  .container,
  footer {
    display: none;
  }

  .loader {
    display: flex;
  }
}

在速度足够快的网络和设备,或者原生支持容器查询的设备上,永远不会显示此加载指示器。

新的 Polyfill 功能

更新后的 polyfill 支持:

  • 嵌套的 @container 规则。
  • 支持将 @container 规则嵌套在 @supports@media 查询下,反之亦然。
  • 在 polyfill 加载后,@supports (container-type: inline-size) 等条件 CSS 将通过。
  • 全面支持 CSS 语法(在语法上有效的任何位置添加注释都不会再出现任何问题)。
  • 垂直书写模式(通过书写模式)。
  • 查询条件、属性声明和动画关键帧支持容器相对单位 (cqwcqh 等)。 查询条件支持 remem
  • 展开后的容器查询语法:
    • 范围语法(例如 (200px < width < 400px))。
    • 等式查询(例如 (width = 200px))。
  • ::before::after 等伪元素。
  • 没有 :is(...)/:where(...) 的浏览器可通过可选的权宜解决方法获得支持
  • orientationaspect-ratio 功能查询。
  • 根据功能正确过滤查询(例如,在水平写入模式下正确禁止对 container: inline-size 查询 height)。
  • DOM 变异(例如,在运行时移除 <style><link> 元素)。

多填充限制和警告

如果您使用的是容器查询 polyfill,请注意以下缺少的功能:

  • 系统尚不支持 Shadow DOM。
  • @media 查询条件不支持容器相对单位(例如 cqwcqh)。
    • Safari:15.4 之前的动画关键帧不支持容器相对单位。
  • 查询条件尚不支持 calc()min()max() 或其他数学函数。
  • 此 polyfill 仅适用于内嵌和同源 CSS。不支持跨源样式表和 iframe 中的样式表(除非手动加载 polyfill)。
  • layoutstyle 容器需要底层浏览器支持:
    • Safari 15.4 及更高版本
    • Firefox 目前不支持样式嵌套,但正在努力实现该功能。

警告

  • 为避免影响 FIDCLS,该 polyfill 不保证何时会发生首次布局,即使同步加载也是如此,但会尝试避免不合理地延迟 LCP。换句话说,您绝不应依赖于它来实现首次绘制。
  • 生成 ResizeObserver Loop Errors。原始 polyfill 也会执行此操作,但值得注意。之所以会出现这种情况,是因为 container-type: inline-size 的块大小在评估查询后可能会发生变化,但 ResizeObserver 无法告知它我们不关心块大小的变化。
  • 此 polyfill 根据 Web 平台测试进行了测试,由于某些功能(如 JavaScript API)并未通过 polyfill,因此通过率会有意接近 70%,达到 70% 的通过率。
  • 2.23% 使用低于以下版本的浏览器的用户需要使用 :where() 权宜解决方法
    • Safari 14
    • Chromium 88
    • Edge 88
    • Samsung Internet 15
    • Firefox 78