CSS 容器查询技术日渐成熟,许多开发者开始尝试应用于各种项目,即使只是简单的实验。虽然浏览器支持度并非完全普及,但在某些项目中已足够实用,但可能还不足以完全取代旧项目中的媒体查询。
容器查询确实非常方便!事实上,我已经遇到过几次情况,非常希望用到它,但却受限于浏览器兼容性。如果当时可以使用容器查询,效果将会更好。
以下所有演示在撰写本文时,最好在 Chrome 或 Safari 中查看。Firefox 计划在 109 版本中提供支持。
这个案例大家应该都比较熟悉,对吧?这是一个非常常见的模式,我们几乎都会遇到。但事实是,如果可以使用容器查询而不是标准媒体查询,将会节省大量时间,并获得更好的结果。
假设您需要构建一个卡片网格,要求每个卡片保持 1:1 的纵横比:
这比看起来要难!问题在于,根据视口宽度调整组件内容大小,会让您受制于组件对视口的响应方式,以及任何其他祖先容器对视口的响应方式。例如,如果您希望当卡片达到特定内联大小时,卡片标题的字体大小减小,则没有可靠的方法可以做到这一点。
您可以使用 vw 单位设置字体大小,但是组件仍然与浏览器的视口宽度绑定。当卡片网格在其他可能没有相同断点的上下文中使用时,这可能会导致问题。
在我的实际项目中,我采用了 JavaScript 方法:
看起来工作量很大,对吧?但这是一个稳定的解决方案,可以在不同屏幕尺寸和不同上下文中实现所需的缩放。
容器查询将会更好,因为它提供了容器查询单位,例如 cqw 单位。您可能已经了解,1cqw 等于容器宽度的 1%。我们还有 cqi 单位,它是容器内联宽度的度量,cqb 用于容器块宽度。因此,如果我们有一个 500px 宽的卡片容器,则 50cqw 的值计算为 250px。
如果在我的卡片网格中可以使用容器查询,我可以将 .card
组件设置为容器:
.card {
container: card / size;
}
然后,我可以使用 cqw 单位设置一个具有填充的内部包装器,该包装器按 .card
宽度的 10% 缩放:
.card__inner {
padding: 10cqw;
}
这是一种不错的方法,可以一致地缩放卡片边缘与其内容之间的间距,无论卡片在任何给定视口宽度下在何处使用。无需媒体查询!
另一个想法?使用 cqw 单位作为内部内容的字体大小,然后使用 em 单位应用填充:
.card__inner {
font-size: 5cqw;
padding: 2em;
}
5cqw 是一个任意值——我只是选择了一个值。该填充仍然等于 10cqw,因为 em 单位相对于 .card__inner
字体大小!
您注意到了吗?2em 相对于在同一容器上设置的 5cqw 字体大小!容器的工作方式与我们习惯的不同,因为 em 单位相对于同一元素的字体大小值。但我很快注意到,容器查询单位与最近的父级(也是容器)相关。
例如,在这个例子中,5cqw 不会根据 .card
元素的宽度缩放:
.card {
container: card / size;
container-name: card;
font-size: 5cqw;
}
相反,它会缩放至定义为容器的最近父级。这就是为什么我设置了一个 .card__inner
包装器。
在另一个项目中,我还需要另一个卡片组件。这次,我需要卡片在屏幕变小时从横向布局过渡到纵向布局……然后再次回到横向布局,再回到纵向布局。
我完成了这项艰巨的工作,使该组件在两个特定的视口范围内变为纵向(向新的媒体查询范围语法致敬!),但问题是它随后被锁定在对其、其父级以及可能响应视口宽度的任何其他内容设置的媒体查询上。我们需要一种在任何情况下都能工作的东西,而不用担心内容将在哪里中断!
由于使用了 @container
规则,容器查询可以轻松解决这个问题:
.info-card {
container-type: inline-size;
container-name: info-card;
}
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
一个查询,无限流畅:
但是等等!您可能需要注意一些问题。具体来说,在基于 prop 的设计系统中使用这样的容器查询可能很困难。例如,此 .info-card
组件可能包含依赖于 prop 来更改其外观的子组件。
为什么这很重要?卡片的纵向布局可能需要备用样式,但您无法使用 CSS 更改 JavaScript prop。因此,您可能会重复所需的样式。我在另一篇文章中实际讨论了这一点以及如何解决这个问题。如果您需要将容器查询用于大量样式,那么您可能需要围绕它们构建整个设计系统,而不是试图将它们塞入一个依赖媒体查询的现有设计系统中。
这是我最近使用过的另一个非常常见的模式,如果使用容器查询,将会得到更完善的产品。假设您有一个与标题锁定的图标:
Heading
即使没有媒体查询,也很容易根据标题的大小缩放图标。但是,问题是 SVG 的 stroke-width
在较小尺寸下可能会太细而难以注意到,而在较大尺寸下可能会过于粗而过于显眼。
我不得不为每个图标实例创建和应用类来确定其大小和描边宽度。如果图标位于使用固定字体大小的标题旁边,这还可以,但是当使用不断变化的流体类型时,效果就不那么好了。
标题的字体大小可能基于视口宽度,因此 SVG 图标需要相应地调整其描边在任何大小下都能正常工作。您可以通过使用 em 单位设置描边宽度使其相对于标题的字体大小。但是,如果您需要坚持使用一组特定的描边大小,则此方法无效,因为它会线性缩放——如果没有在视口宽度上使用媒体查询,则无法将其调整到特定描边宽度值,而不会诉诸于视口宽度上的媒体查询。
但是,如果我有机会使用容器查询,我会这样做:
.icon {
container: icon / size;
width: 1em;
height: 1em;
}
.icon svg {
width: 100%;
height: 100%;
fill: none;
stroke: #ccc;
stroke-width: 0.8;
}
@container icon (max-width: 70px) {
.icon svg {
stroke-width: 1.5;
}
}
@container icon (max-width: 35px) {
.icon svg {
stroke-width: 3;
}
}
比较这些实现,看看容器查询版本如何根据容器的宽度将 SVG 的描边捕捉到我想要的特定宽度。
好的,我实际上并没有在实际项目中遇到这种情况。但是,当我仔细研究容器查询的信息时,我注意到我们可以查询与容器大小或物理尺寸相关的容器的其他内容。
我在这篇文章中一直在使用的示例大多查询宽度、最大宽度和最小宽度、高度、块大小和内联大小。
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
但是 MDN 概述了我们可以查询的另外两件事。一个是方向,这非常有意义,因为我们一直在媒体查询中使用它。容器查询也是如此:
@media screen (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
@container info-card (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
另一个是纵横比,信不信由你:
@container info-card (aspect-ratio: 3/2) {
.info-card__inner {
/* Style away! */
}
}
这是一个可编辑的演示,可以用来试验这两个例子:
我还没有真正找到这两个的良好用例。如果您有任何想法或觉得它可以帮助您完成项目,请在评论中告诉我!
Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.
Copyright© 2022 湘ICP备2022001581号-3