在 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。此 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。

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

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

  .loader {
    display: flex;
  }
}

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

新的 Polyfill 功能

更新后的 polyfill 支持:

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

Polyfill 限制和警告

如果您使用的是容器查询 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
    • 铬 88
    • Edge 88
    • 三星互联网 15
    • Firefox 78