CSS的发展:关于CSS容器查询的探讨

当我说 “即将到来” 时,我的意思是它还没有被任何浏览器支持,而且规格也没有最终确定(在写这篇文章的时候)。也就是说,它在下一个版本的Chrome中是一个标志,而且我毫不怀疑它很快就会出现在所有 “现代” 浏览器中。

什么是容器查询

容器查询类似于媒体查询,但有一个主要的,也是关键的区别。媒体查询可以查询整个文档,并根据这些查询来修改内容。例如,如果文档超过1025px,你可能想把内容移到两列而不是一列。这将看起来像这样。

main.content {

column-count: 1;

column-gap: 2em;

}

@media screen and (min-width: 1025px) {

main.content {

column-count: 2;

}

}

容器查询遵循同样的原则,但不是查询整个文档,而是查询容器。

他们是如何帮助开发者的

想象一下下面的情况;你有一个联系卡,你想在你的网站上到处显示。在一些地方,它在主要内容中,但在其他地方,你决定将它显示在一个旁侧。在同一个媒体查询中,旁白可能是250px,但主要部分可能是700px,导致卡片需要看起来不同。解决这个问题很简单,你需要用不同的媒体查询为卡片设置不同的类,但还有一个更好的方法…… 容器查询!

如何使用容器查询

要使用容器查询,我们必须告诉容器(我们想要应用查询的元素的父级)我们关心它的尺寸,我们用新的 contain 属性来做。

  • none –表示该元素以正常方式呈现,没有应用任何包含规则。
  • strict –表示除样式外的所有包含规则都应用于该元素。这等同于 contain: size layout paint。
  • content –表示除了size和style之外的所有包含规则都应用于该元素。这等同于包含:layout paint。
  • size –表示该元素可以被调整大小,而不需要检查其后代的大小。
  • layout –表示元素外部的任何东西都不能影响其内部布局,反之亦然。
  • style – 表示对于那些可以对不止一个元素和它的子元素产生影响的属性,这些影响不会转移到包含元素。请注意,这个值在规范中被标记为 “at-risk”,可能不会在任何地方被支持。
  • paint –表示该元素的后代不会显示在其边界之外。如果包含的盒子在屏幕外,浏览器不需要画出其包含的元素–这些元素也必须在屏幕外,因为它们完全被该盒子所包含。如果一个后代超出了包含元素的边界,那么这个后裔将被剪裁到包含元素的边界框中。

目前Mozilla上的文档有点缺失,这很罕见。我们想使用 inline-size 属性,在Mozilla的其他地方描述为

当我们使用媒体查询时,大多数时候我们关心的是可用宽度(或 inline-size )。

实践例子

让我们以前面的联系卡为例,想出一些代码来描述它。

<div>

<main>

<div>

<img src="profile.png" alt="profile" />

<div>

<h1>Both Names</h1>

<p>Some info about me</p>

</div>

</div>

</main>

<aside>

<div>

<img src="profile.png" alt="profile" />

<div>

<h1>Both Names</h1>

<p>Some info about me</p>

</div>

</div>

</aside>

</div>

这个HTML是相当简单的,但我认为它表达了一个观点,我们有一个联系卡,它在两个地方,有可能有极大的不同宽度。

/* Just some simple css to get it started */

.site {

display: flex;

max-width: 800px;

margin: 0 auto;

}

main.content {

width: 60%;

background: #ccc;

}

aside.side-panel {

width: 40%;

background: tomato;

}

/* Real css starts here */

main.content, aside.side-panel {

contain: layout inline-size;

}

.contact-card {

display: flex;

flex-direction: column;

align-items: center;

width: 200px;

background-color: white;

padding: 2em;

box-sizing: border-box;

border-radius: 2px;

margin: 1em;

box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 1px 1px rgba(0, 0, 0, 0.4)

}

.contact-card__profile-image {

height: 50px;

width: 50px;

border-radius: 50px;

border: 1px solid black;

}

.contact-card__profile-information {

margin-left: 0.5em;

}

.contact-card__profile-information h1 {

text-align: center;

margin: 0;

font-size: 1.2em;

}

.contact-card__profile-information p {

text-align: center;

margin: 0.5em 0 0 0;

}

@container (min-width: 450px) {

.contact-card {

width: 300px;

flex-direction: row;

align-items: flex-start;

}

.contact-card__profile-information h1 {

text-align: left;

}

.contact-card__profile-information p {

text-align: left;

}

}

在这个CSS中,我们为 contact-card 设计了样式,然后我们有一个容器查询,当我们传递450px的宽度时,它就会改变卡片的样式。正如你所看到的,它基本上与媒体查询相同,但它是基于容器的。

下面是代码的呈现方式(希望有一天我们能在更多的浏览器中试用)。这里是代码,如果在实际工作中,jsfiddle。

代码的呈现方式

影响规范化

正如我在一开始所说的,规范还没有最终确定,如果你想看看人们的建议,或者你想自己提出建议,现在还有时间去做。请到git issues板上看一看。

小结

我对此非常兴奋,我主要是用React工作,我真的很期待组件能够根据其父级的大小来改变。