容器查询通常被认为是一种现代的响应式网页设计方法,传统的媒体查询长期以来一直是黄金标准——原因是我们可以创建由对容器宽度响应的元素构成的布局,而不是对视窗宽度响应的布局。
.parent {
container-name: hero-banner;
container-type: inline-size;
/* or container: hero-banner / inline-size; */
}
}
.child {
display: flex;
flex-direction: column;
}
/* When the container is greater than 60 characters... */
@container hero-banner (width > 60ch) {
/* Change the flex direction of the .child element. */
.child {
flex-direction: row;
}
}
为什么要关注 CSS 容器查询?
- 使用容器查询时,我们使元素能够根据其容器的大小而不是视窗的大小进行更改。
- 它们允许我们以更可预测的方式定义特定元素的所有样式。
- 它们比媒体查询更可复用,因为它们在任何地方使用时都具有相同的行为。因此,如果您要创建包含容器查询的组件,可以轻松地将其放入另一个项目中,它仍然会以相同的可预测方式运行。
- 它们引入了新的 CSS 长度单位类型,可以使用这些单位根据容器的大小对元素进行大小调整。
将元素注册为容器
.cards {
container-name: card-grid;
container-type: inline-size;
/* Shorthand */
container: card-grid / inline-size;
}
此示例注册了一个名为 card-grid
的新容器,可以通过其 inline-size
进行查询,这是一个表示我们在水平书写模式下“宽度”的更正式的说法。它是一个 逻辑属性。否则,“内联”将在垂直书写模式下指的是容器的“高度”。
container-name
属性用于将元素注册为容器,该容器根据容器的大小和样式对其他元素应用样式。
container-type
属性用于将元素注册为容器,当该元素满足某些条件时,可以对其他元素应用样式。
container
属性是一个简写属性,它将container-name
和container-type
属性合并到一个声明中。
一些可能的陷阱
container-name
属性是可选的。未命名的容器将匹配任何不针对特定容器的容器查询,这意味着它可能匹配多个条件。- 如果我们要根据容器的
size
或inline-size
查询容器,则container-type
属性是必需的。size
指的是容器的内联或块方向,以较大者为准。inline-size
指的是容器在默认水平书写模式下的宽度。 container-type
属性的默认值是normal
。而“normal”意味着所有元素默认都是容器,只是它们被称为样式容器,只能通过其应用的样式进行查询。例如,我们可以查询容器的background-color
值,并在该值是特定颜色值时对其他元素应用样式。- 容器不能更改自己的样式。相反,它们会更改其内容的样式。换句话说,当容器是特定大小时,我们无法更改容器的
background-color
——但我们可以更改容器内部任何元素的background-color
。“您不能对查询的内容进行样式化”是思考问题的一种方式。 - 容器不能根据其内容进行大小调整。通常,元素的内容会影响其大小——例如,内容越多,它就越大,反之亦然。但容器必须作为 flex 或 grid 布局的一部分明确地进行大小调整。
查询容器
@container my-container (width > 60ch) {
article {
flex-direction: row;
}
}
@container
at-规则属性告诉浏览器我们正在使用容器查询,而不是媒体查询(例如,@media
)。
- 其中的
my-container
指的是容器的名称,如容器的container-name
属性中所声明。
article
元素表示容器中的一个项目,无论它是容器的直接子元素还是更远的祖先。无论哪种方式,该元素都必须位于容器中,并且在匹配查询条件时将对其应用样式。
一些可能的陷阱
- 容器的名称是可选的。如果我们省略它,则任何注册的容器在满足条件时都将匹配。
- 当
container-type
属性设置为size 或 inline-size 时,可以查询容器的width
。这是因为size
可以查询元素的width
或height
;而inline-size
只能指的是width
。 - 您可以查询任何长度。因此,除了
width
(即,inline-size
)之外,还有元素的aspect-ratio
、block-size
(即,height
)和方向(例如,portrait
和landscape
)。 - 查询支持范围语法。到目前为止,大多数示例都显示了“大于”(
>
)和“小于”(<
),但也有“等于”(=
)以及三者的组合,例如“大于或等于”(>=
)和“小于或等于”(<=
)。 - 查询可以链接。这意味着我们可以使用逻辑关键字(如
and
、or
和not
)编写满足多个条件的查询。
容器查询属性和值
容器查询属性和值
container-name
container-name: none | <custom-ident>+;
值描述
none
: 元素没有容器名称。这是默认情况,因此您可能永远不会使用此值,因为它的目的是纯粹设置属性的默认行为。<custom-ident>
: 这是容器的名称,可以是任何内容,但不能是为其他功能保留的单词,包括default
、none
、at
、no
和or
。请注意,名称没有用引号括起来。
- 初始值:
none
- 应用于: 所有元素
- 继承: 否
- 百分比: 不适用
- 计算值:
none
或标识符的排序列表 - 规范顺序: 根据语法
- 动画: 不可动画
container-type
container-type: normal | size | inline-size;
值描述
normal
: 这表示该元素是一个容器,可以通过其样式而不是大小进行查询。 所有元素默认情况下都是容器,因此我们甚至不需要明确地分配container-type
来定义样式容器。size
: 如果我们要根据容器的大小查询容器,无论是内联方向还是块方向。inline-size
: 这允许我们根据容器的内联大小查询容器,在标准水平书写模式下等同于width
。这可能是最常用的值,因为我们可以根据元素的大小来建立响应式设计,而不是像通常使用 媒体查询那样根据视窗的大小来建立。
- 初始值:
normal
- 应用于: 所有元素
- 继承: 否
- 百分比: 不适用
- 计算值: 按关键字指定
- 规范顺序: 根据语法
- 动画: 不可动画
container
container: <'container-name'> [ / <'container-type'> ]?
值定义
如果省略了<'container-type'>
,它将被重置为其初始值normal
,该值定义了一个样式容器而不是大小容器。换句话说,所有元素默认情况下都是样式容器,除非我们显式地将container-type
属性值设置为size
或inline-size
,这使我们能够查询容器的大小尺寸。
- 初始值:
none
/normal
- 应用于: 所有元素
- 继承: 否
- 百分比: 不适用
- 计算值:如指定
- 规范顺序: 根据语法
- 动画: 不可动画
容器长度单位
容器宽度和高度单位
单位 | 名称 | 相当于… |
---|---|---|
cqw | 容器查询宽度 | 查询容器宽度的 1% |
cqh | 容器查询高度 | 查询容器高度的 1% |
容器逻辑方向
单位 | 名称 | 相当于… |
---|---|---|
cqi | 容器查询内联大小 | 查询容器内联大小的 1%,在水平书写模式下为其宽度。 |
cqb | 容器查询块大小 | 查询容器内联大小的 1%,在水平书写模式下为其高度。 |
容器最小和最大长度
单位 | 名称 | 相当于… |
---|---|---|
cqmin | 容器查询最小尺寸 | cqi 或 cqb 的值,以较小的那个为准。 |
cqmax | 容器查询最大尺寸 | cqi 或 cqb 的值,以较大的那个为准。 |
容器样式查询
容器样式查询是 CSS 容器查询拼图的另一个部分。我们不需要根据容器的size
或inline-size
来查询容器,而是可以查询容器的 CSS 样式。当容器的样式满足查询条件时,我们可以将样式应用于其他元素。这是我们长期以来在 Web 上想要的“条件”样式:如果这些样式在这里匹配,则在其他地方应用这些其他样式。
CSS 容器样式查询在撰写本文时仅作为现代 Web 浏览器中的实验性功能提供,即使那样,样式查询也只能够评估 CSS 自定义属性(即变量)。
浏览器支持
在撰写本文时,该功能仍然被认为是实验性的,并且不受任何浏览器的支持,除非通过功能标志启用。
此浏览器支持数据来自Caniuse,其中包含更多详细信息。数字表示浏览器在该版本及其更高版本中支持该功能。
桌面
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
130 | 否 | 否 | 127 | TP |
移动/平板
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
127 | 否 | 127 | 18.0 |
注册样式容器
article {
container-name: card;
}
就是这样!实际上,我们甚至不需要container-name
属性,除非我们需要专门定位它。否则,我们可以跳过注册容器。
如果您想知道为什么没有container-type
声明,那是因为所有元素都被认为是容器。这很像所有元素默认情况下都是position: relative
;不需要声明它。我们声明container-type
的唯一原因是,如果我们想要 CSS 容器大小查询而不是 CSS 容器样式查询。
因此,实际上,不需要注册容器样式查询,因为所有元素开箱即用都是样式容器!因此,我们声明container-name
的唯一原因仅仅是为了在编写样式查询时帮助按名称选择特定容器。
使用样式容器查询
@container style(--bg-color: #000) {
p { color: #fff; }
}
在本例中,我们查询任何匹配的容器(因为所有元素默认情况下都是样式容器)。
请注意,语法与传统的媒体查询非常相似?最大的区别是,我们正在编写@container
而不是@media
。另一个区别是,我们正在调用一个包含匹配样式条件的style()
函数。这样,样式查询就与大小查询区分开来,尽管没有相应的size()
函数。
在本例中,我们正在检查名为--bg-color
的特定自定义属性是否设置为黑色 (#000
)。如果变量的值与该条件匹配,那么我们将段落 (p
) 文本的color
设置为白色 (#fff
)。
自定义属性和变量
.card-wrapper {
--bg-color: #000;
}
.card {
@container style(--bg-color: #000) {
/* Custom CSS */
}
}
嵌套样式查询
@container style(--featured: true) {
article {
grid-column: 1 / -1;
}
@container style(--theme: dark) {
article {
--bg-color: #000;
--text: #fff;
}
}
}
规范
CSS 容器查询在CSS Containment Module Level 3 规范中定义,该规范目前处于撰写本文时的编辑草案状态。
浏览器支持
CSS 容器大小查询的浏览器支持情况很好。只是在撰写本文时,样式查询缺乏支持。
- Chrome 105 于 2022 年 8 月 30 日发布,支持该功能。
- Safari 16 于 2022 年 9 月 12 日发布,支持该功能。
- Firefox 110 于 2023 年 2 月 14 日发布,支持该功能。
此浏览器支持数据来自Caniuse,其中包含更多详细信息。数字表示浏览器在该版本及其更高版本中支持该功能。
桌面
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
106 | 110 | 否 | 106 | 16.0 |
移动/平板
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
127 | 127 | 127 | 16.0 |
演示!
网上有很多例子演示了容器查询是如何工作的。以下例子在说明容器查询的一般概念方面并不独特,因为它们说明了在容器元素满足特定条件时应用样式的一般概念。
您将在本指南末尾的参考资料中找到更多示例,但请查看Ahmad Shadeed 的容器查询实验室,以获取最完整的示例集,因为它也用作巧妙的容器查询用例的集合。
卡片组件
在本例中,“卡片”组件根据其容器中的可用空间量更改其布局。
号召性用语面板
这个例子很像那些用来订阅电子邮件通讯的小面板。请注意布局如何根据容器中可用的空间大小变化三次。这就是 CSS 容器查询如此强大的原因:你可以将这个面板放到任何项目中,布局都会按照预期进行响应,因为它是基于它所处的空间而不是浏览器视窗的大小。
步进器组件
此组件显示一系列“步骤”,就像时间线一样。在较宽的容器中,步进器会水平显示步骤。但是,如果容器变得足够小,步进器就会调整布局,使步骤垂直堆叠。
图标按钮
有时我们喜欢用图标装饰按钮,以用更多含义和上下文来突出显示按钮的标签。有时我们不知道这个按钮在任何给定上下文中会有多宽,这使得很难知道何时隐藏图标或在空间变得有限时重新排列按钮的样式。在这个例子中,只要有空间容纳图标和按钮标签,图标就会显示在按钮的右边缘。如果空间不足,按钮就会变成一个正方形,将图标堆叠在标签之上。请注意,border-radius
是如何以 **容器查询单位** 4cqi
设置的,它等于容器内联大小(即宽度)的 4%,并且随着按钮尺寸增大,边角变得更圆。
分页
分页是一个很好的例子,它可以从 CSS 容器查询中获益,因为根据我们拥有的空间量,我们可以选择显示指向各个页面的链接,或者隐藏它们,只显示两个按钮,一个用来翻页到较旧的内容,另一个用来翻页到较新的内容。
文章和教程
一般信息
容器尺寸查询教程
容器样式查询
参考
- 容器查询:快速入门指南 (OddBird)
- CSS 容器,它们知道什么? (OddBird)
- CSS 容器查询入门 (Smashing Magazine)
- CSS 容器查询:用例和迁移策略 (Smashing Magazine)
- CSS 容器查询交互式指南 (以及 演示) (Ahmad Shadeed)
- 容器查询 – 在浏览器中设计 (web.dev)
- CSS 容器查询 (Mozilla Developer Network)
- 容器查询将改变我们制作布局的方式 (Kevin Powell)
- 容器查询和单位 (Zach Saucier)
- 容器查询单位和流体排版 (ModernCSS)
你好。感谢提醒有关容器查询的信息。
但是,默认情况下所有元素的位置不都是
static
吗?是啊,那一部分让我愣了一下。我得检查一下规范是否有什么变化!但没错,所有元素的位置默认情况下仍然是 static,而不是 relative。
但是仍然不可能创建一个规则,如果容器的高度具有特定值,则允许应用特定样式,对吧?
举个简单的例子
以下是如何经常使用容器查询来创建响应式布局
但假设我们需要做一些事情,比如如果我们的卡片太高,就创建雾化淡出效果
它不会起作用,因为我们使用 `inline-size` 作为容器类型 `card`。但如果我们将类型更改为 `size`,我们**必须**为容器使用特定高度(但我们实际上不知道它在页面上的高度,因为内容不同,我们只是想确保我们的卡片不会过大,并隐藏内容,显示一些额外的 UI 元素等等)。
关于我遇到的一个问题。当我使用一个卡片列表,其中每个卡片都使用容器查询显示,并且我使用工具提示(NuxtUI 库)时,如果下一个卡片的文本与工具提示重叠,则该文本将出现在工具提示的前面。当我从卡片中删除“容器查询”部分时,工具提示会正确显示。这是因为堆叠顺序吗?还是有解决方法?