Chrome 正在试验 @container
,这是 CSS 工作组 包含级别 3 规范 中的一个属性,由 Miriam Suzanne(来自 Oddbird)和一组跨网络平台的工程师推动。 @container
使我们能够根据元素的父容器大小来设置元素的样式。
您可以将这些视为媒体查询(@media
),但不同的是,它们不依赖于视口来调整样式,而是依赖于您正在定位的元素的父容器来调整这些样式。
容器查询将是自 CSS3 以来 Web 样式方面最大的变化,改变了我们对“响应式设计”的理解。
视口和用户代理不再是我们创建响应式布局和 UI 样式的唯一目标。 借助容器查询,元素将能够定位自己的父级并相应地应用自己的样式。 这意味着,位于侧边栏、主体或英雄区域中的同一个元素,根据其可用大小和动态特性,可能会呈现完全不同的外观。
@container
的作用
在这个例子中,我在一个父级中使用了两个卡片,其标记如下
<div class="card-container">
<div class="card">
<figure> ... </figure>
<div>
<div class="meta">
<h2>...</h2>
<span class="time">...</span>
</div>
<div class="notes">
<p class="desc">...</p>
<div class="links">...</div>
</div>
<button>...</button>
</div>
</div>
</div>
然后,我在要查询容器样式的父级(.card-container
)上设置包含(container-type
属性)。 我还在 .card-container
的父级上设置了相对网格布局,因此它的 inline-size
将根据该网格进行更改。 这就是我使用 @container
查询的内容
.card-container {
container-type: inline-size;
width: 100%;
}
现在,我可以查询容器样式来调整样式! 这与您使用基于宽度的媒体查询设置样式的方式非常相似,使用 max-width
在元素小于某个大小时设置样式,使用 min-width
在元素大于某个大小时设置样式。
/* when the parent container is smaller than 850px,
remove the .links div and decrease the font size on
the episode time marker */
@container (max-width: 850px) {
.links {
display: none;
}
.time {
font-size: 1.25rem;
}
/* ... */
}
/* when the parent container is smaller than 650px,
decrease the .card element's grid gap to 1rem */
@container (max-width: 650px) {
.card {
gap: 1rem;
}
/* ... */
}
容器查询 + 媒体查询
容器查询最好的功能之一是能够将微布局与宏布局分开。 您可以使用容器查询对单个元素进行样式设置,创建细致入微的微布局,并使用媒体查询对整个页面布局进行样式设置,从而创建宏布局。 这创建了一个新的控制级别,可以实现更具响应性的界面。
以下是一个例子,它展示了使用媒体查询进行宏布局(例如,日历从单面板变为多面板)和微布局(例如,日期布局/大小和事件边距/大小发生变化)的强大功能,以创建美妙的查询交响乐。
容器查询 + CSS 网格
我个人最喜欢的一个展示容器查询效果的方法是观察它们在网格中的工作方式。 以下是一个植物商务 UI 的例子
此网站完全不使用媒体查询。 相反,我们只使用容器查询和 CSS 网格来在不同视图中显示购物卡片组件。
在产品网格中,布局使用 grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
创建。 这创建了一个布局,告诉卡片使用可用的分数空间,直到它们的大小达到 230px
,然后流到下一行。 更多网格技巧请访问 1linelayouts.com。
然后,我们有一个容器查询,它将卡片的样式设置为在它们宽度小于 350px
时采用垂直块布局,并在应用 display: flex
时(默认情况下具有内联流)切换到水平内联布局。
@container (min-width: 350px) {
.product-container {
padding: 0.5rem 0 0;
display: flex;
}
/* ... */
}
这意味着每张卡片都拥有自己的响应式样式。 这是另一个您可以使用产品网格创建宏布局,并使用产品卡片创建微布局的例子。 非常酷!
用法
要使用 @container
,您首先需要创建一个具有 包含性 的父元素。 为此,您需要在父元素上设置 contain: layout inline-size
。 您可以使用 inline-size
,因为我们目前只能将容器查询应用于内联轴。 这将防止您的布局在块方向上断裂。
设置 contain: layout inline-size
将创建一个新的 包含块 和新的 块格式化上下文,让浏览器将其与布局的其余部分分离。 现在,我们可以进行查询!
局限性
目前,您无法使用基于高度的容器查询,只能使用块轴。 为了让网格子元素与 @container
一起使用,您需要添加一个包装元素。 尽管如此,添加包装器仍然可以实现您想要的效果。
试一试
您可以在今天的 Chromium 中试验 @container
属性,方法是在 Chrome Canary 中导航到:chrome://flags
并打开#experimental-container-queries 标志。

你可以查询多个容器吗?
我认为不行,但我还在努力理解这一切。我相信在当前的规范中,你甚至不能指定一个容器。它假设你指的是你所选择元素的父元素。
是的!你可以设置多个父元素的 containment 属性,并针对这些父元素进行查询。
所以我们在
@container
内编写查询,它引用具有指定contain
属性的单个父容器。如果你想要多个容器,这将如何工作?@container
内选择器所针对的任何元素都将查询其最近的祖先容器。因此,如果你将.sidebar
和main
都设置为容器,你可以将元素放在其中任何一个中,每个元素都将查询其所在的容器。你可以根据需要嵌套容器,元素将始终查询最接近的容器。想到这终于要成为现实,感觉很奇怪。
非常感谢所有参与使这成为可能的人!
容器查询、网格和 Web 组件,现在没有什么能阻止我们了(闭嘴,Safari!)
酷!有没有办法使用不同的容器?或者你需要在选择器中引用父元素?
是的!你可以设置多个父元素的 containment 属性,并针对这些父元素进行查询。
希望很快看到它最终确定,它是使 UI 组件可重用的圣杯。
我想知道它距离在官方 Chrome 版本中引入还有多远
将它作为原生 CSS 功能会非常棒!
在此之前,幸运的是有一些库 :)
例如,在这个演示中有很多容器查询
https://tobireif.com/demos/grid/
它使用库 https://github.com/eqcss/eqcss/ 及其语法。
非常酷 Tobi
所以它或多或少是 CSS 等效于 resize observer——我很久以前就希望有这样的东西!
polyfill 使用 resize observer :) https://github.com/jsxtools/cqfill
嗨。关于向网格元素添加
@container
的限制。这将是我们必须在容器查询的发布版本中解决的问题,还是会有办法使网格元素成为容器而不必添加包装元素?谢谢!
这听起来像一个我可以用来制作墓地网站的技巧,使用网格来表示单个墓地,并使用查询来根据大小更改有关埋葬在该地块中的人的信息的数量和类型。令人兴奋!
我假设这将像 backdrop-filter 一样在实验中待上几年。我们真正想要的东西,可能已经完美工作了,但我们却要等上好几年才会看到。
希望我错了,但我敢打赌至少要等一年才会实现。