CSS 容器查询仍在获得关注,我们中的许多人都在接触它们,即使它只是为了小实验或诸如此类的东西。 他们有很棒的,但不是很饱, 浏览器支持 - 足以证明在某些项目中使用它们是合理的,但可能还没有达到我们可能想要开始更换的程度 媒体查询 从过去的项目中使用闪亮的新容器大小查询。
不过它们确实很方便! 事实上,我已经遇到过一些我真的很想联系他们但无法克服支持要求的情况。 如果我能够使用它们,这就是它在那些情况下的样子。
在撰写本文时,最好在 Chrome 或 Safari 中查看以下所有演示。 Firefox 计划 船舶支援 在版本 109 中。
案例一:卡片网格
你有点期待这个,对吧? 这是一个如此普遍的模式,以至于我们所有人似乎都在某个时候遇到过它。 但事实是,如果我能够在标准媒体查询上使用它们,容器大小查询对我来说会节省大量时间并获得更好的结果。
假设您的任务是构建此卡片网格,要求每张卡片都需要保持 1:1 的纵横比:
它比看起来更难! 问题是根据视口的宽度调整组件内容的大小会让您受制于组件对视口的响应方式——以及任何其他祖先容器对它的响应方式。 例如,如果您希望卡片标题的字体大小在卡片达到特定行内大小时减小,则没有可靠的方法可以做到这一点。
你可以设置字体大小 vw
单位,我想,但组件仍然依赖于浏览器的视口宽度。 当在可能没有相同断点的上下文中使用卡片网格时,这可能会导致问题。
在我的实际项目中,我找到了一种 JavaScript 方法,它可以:
- 监听调整大小事件。
- 计算每张卡片的宽度。
- 根据卡片的宽度为每张卡片添加内联字体大小。
- 使用里面的所有样式
em
单位。
看起来工作量很大,对吧? 但它是一个稳定的解决方案,可以在不同的上下文中跨不同的屏幕尺寸进行所需的缩放。
容器查询会好得多,因为它们为我们提供了 容器查询单元, 如那个 cqw
单元。 你可能已经明白了,但是 1cqw
等于 1%
一个容器的宽度。 我们还有 cqi
衡量容器内联宽度的单位,以及 cqb
对于容器的块宽度。 所以,如果我们有一个卡片容器 500px
宽,一个 50cqw
值计算为 250px
.
如果我能够在我的卡片网格中使用容器查询,我就可以设置 .card
作为容器的组件:
.card {
container: card / size;
}
然后我可以设置一个内包装 padding
规模为 10%
的 .card
的宽度使用 cqw
单元:
.card__inner {
padding: 10cqw;
}
这是一种很好的方式来缩放卡片边缘与其内容之间的间距,无论在任何给定的视口宽度下卡片在何处使用。 无需媒体查询!
另一个想法? 利用 cqw
内部内容的字体大小的单位,然后应用填充 em
单位:
.card__inner {
font-size: 5cqw;
padding: 2em;
}
5cqw
是一个任意值——只是我确定的一个值。 该填充仍然等于 10cqw
自 em
单位是相对于 .card__inner
字体大小!
你明白了吗? 这 2em
是相对于 5cqw
设置的字体大小 在同一个容器上. 容器的工作方式与我们习惯的不同,因为 em
单位是相对于同一元素的 font-size value
. 但我很快注意到容器查询单元与 也是容器的最近父级.
例如, 5cqw
不缩放基于 .card
本例中元素的宽度:
.card {
container: card / size;
container-name: card;
font-size: 5cqw;
}
相反,它会扩展到定义为容器的最近父级。 这就是为什么我设立了一个 .card__inner
包装。
案例 2:交替布局
我在不同的项目中需要另一个卡片组件。 这一次,我需要卡片从横向布局转换为纵向布局……然后返回横向,并随着屏幕变小再次返回纵向。
我做了一些肮脏的工作,让这个组件在这两个特定的视口范围内变成纵向(向 新的媒体查询范围语法!),但同样,问题是它随后被锁定到在其上设置的媒体查询、其父级以及可能响应视口宽度的任何其他内容。 我们想要在任何条件下都能工作的东西,而不用担心内容会在哪里中断!
容器查询会让这变得轻而易举,多亏了 @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
组件可以包含依赖道具来改变其外观的子组件。
这有什么大不了的? 卡片的纵向布局可能需要替代样式,但您不能使用 CSS 更改 JavaScript 道具。 因此,您冒着复制所需样式的风险。 我实际上谈到了这一点 如何在另一篇文章中解决它. 如果您需要对大量样式使用容器查询,那么您可能需要围绕它们构建整个设计系统,而不是试图将它们强行塞入现有的媒体查询繁重的设计系统中。
案例 3:SVG 笔画
这是我最近使用的另一种超级常见模式,其中容器大小查询会产生更精美的产品。 假设您有一个标题锁定的图标:
Heading
使用标题大小缩放图标非常简单,即使没有媒体查询。 但问题是 SVG 的 stroke-width
在较小的尺寸下可能会变得太细以至于无法很好地注意到,并且在较大的尺寸下可能会因为超粗的笔触而引起过多的注意。
我必须为每个图标实例创建并应用类以确定其大小和笔画宽度。 我想,如果图标旁边的标题具有固定字体大小,那没关系,但在使用不断变化的流体类型时,效果就不是很好了。
标题的字体大小可能基于视口的宽度,因此 SVG 图标需要相应地调整其笔划在任何大小下的位置。 您可以使笔画宽度相对于标题的 font-size
通过设置它 em
单位。 但是,如果您需要坚持一组特定的笔划大小,那么这将不起作用,因为否则它会线性缩放 - 无法将其调整为特定的 stroke-width
某些点的值,而不求助于视口宽度上的媒体查询。
但如果我当时有容器查询的奢侈,我会这样做:
.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 的笔划对齐到我想要的特定宽度。
奖励:其他类型的容器尺寸查询
好的,所以我还没有在真正的项目中遇到过这个。 但是当我梳理有关容器查询的信息时,我注意到我们可以在容器上查询与容器大小或物理尺寸相关的其他内容。
我见过的大多数例子都查询 width
, max-width
及 min-width
, height
, block-size
及 inline-size
正如我在整篇文章中所做的那样。
@container info-card (max-width: 500px) {
.info-card__inner {
flex-direction: column;
}
}
但是, MDN 概述了另外两件事 我们可以查询。 一个是 orientation
这非常有意义,因为我们一直在媒体查询中使用它。 这与容器查询没有什么不同:
@media screen (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
@container info-card (orientation: landscape) {
.info-card__inner {
/* Style away! */
}
}
另一个? 它是 aspect-ratio
, 信不信由你:
@container info-card (aspect-ratio: 3/2) {
.info-card__inner {
/* Style away! */
}
}
这是一个可编辑的演示,可用于演示这两个示例:
我还没有真正找到其中任何一个的好用例。 如果您有任何想法或觉得它对您的项目有帮助,请在评论中告诉我!