我写了一些 关于容器样式查询的早期想法 不久前。 现在还为时尚早。 它们已经在 CSS Containment Module Level 1 规范 (目前处于编辑草案状态)但仍有一些未完成的讨论正在进行。
基本思想是我们可以定义一个容器,然后根据计算出的样式有条件地将样式应用于其后代。
@container ? {
/* conditional styles */
}
到目前为止我见过的最好的例子是从类似的东西中删除斜体 ,
及
当它们用于内容已经是斜体的上下文中时:
em, i, q {
font-style: italic; /* default UA behavior */
}
/* When the container's font-style is italic, remove italics from these elements. */
@container style(font-style: italic) {
em, i, q {
font-style: normal;
}
}
这是一般的想法。 但是,如果您不知道的话,该规范的编辑 Miriam Suzanne 保持着一套持续而全面的 关于容器样式查询的个人笔记 这是公开的。 它是前几天更新的,我在那里花了一些时间试图围绕样式查询的更细微的方面进行思考。 这是非官方的东西,但我想我应该记下一些对我来说很突出的东西。 谁知道? 也许这是我们最终可以期待的东西!
每个元素都是一个样式容器
我们甚至不需要明确地分配一个 container-name
or container-type
定义样式容器,因为默认情况下一切都是样式容器。
那么,您看到上面那个删除斜体的例子了吗? 请注意,它不标识容器。 它使用 style()
功能。 那么,查询的是什么容器呢? 这将是 元素的直接父元素 接收应用的样式。 如果不是那样,那就是 下一个最近的相对容器 那优先。
我喜欢。 搜索匹配项的查询非常符合 CSS-y,然后继续冒泡直到找到匹配条件。
我的小脑袋很难理解为什么我们可以摆脱基于样式的隐式容器,但在处理维度查询时却没有那么多,比如 size
和 inline-size
. Miriam 很好地解释了它:
维度查询需要css 遏制 容器的大小、布局和样式,以防止布局循环。 容器是一种广泛应用的侵入性事物,因此作者仔细控制哪些元素是(或不是)大小容器是很重要的。
基于样式的查询没有相同的限制。 在 CSS 中,后代样式已经无法影响祖先的计算样式。 因此不需要包含,并且在将元素建立为 样式查询容器.
(强调我的)
这一切都归结为后果——就一切都是开箱即用的样式查询容器而言,没有任何后果。
- 如果找到容器:针对该容器解决条件。
- 如果多个容器匹配:最近的相对容器优先。
- 如果找不到匹配项:
unknown
回。
那是一样的 其余 CSS 的“宽容”精神.
一个容器可以同时支持维度查询和样式查询
假设我们想要定义一个没有显式样式的查询 container-name
:
@container style(font-style: italic) {
em {
font-style: normal;
}
}
这有效,因为 所有元素都是样式容器,无论 container-type
. 这就是允许我们隐式查询样式并依赖最近匹配的原因。 这完全没问题,因为在创建样式容器时也没有不利的副作用。
我们必须使用显式 container-type
对于维度查询,但对于样式查询则不是那么多,因为每个元素都是样式查询。 这也意味着这个容器既是一种风格 和 维度查询:
.card-container {
container: card / inline-size; /* implictly a style query container as well */
}
从查询中排除容器
也许我们不希望容器参与匹配过程。 那是可以设置的地方 container-type: none
在一个元素上。
.some-element {
container-type: none;
}
显式样式查询容器提供对查询内容的更多控制
比方说,如果我们要为 padding
,没有可靠的方法来确定最匹配的容器,无论我们是使用明确命名的容器还是最近的直接父容器。 那是因为 padding
不是继承的财产。
所以,在那些情况下,我们应该使用 container-name
明确通知浏览器他们可以从哪些容器中提取。 我们甚至可以给一个容器多个明确的名字,让它匹配更多的条件:
.card {
container-name: card layout theme;
}
哦, container-name
接受任意数量的可选和 可重复使用 容器的名称! 在帮助浏览器在搜索匹配项时做出选择时,这更加灵活。
.theme {
container-name: theme;
}
.grid {
container-name: layout;
}
.card {
container-name: card layout theme;
}
我有点想知道,如果一个容器被忽略,是否也可以将其视为“后备”。
样式查询可以组合
or
和 and
运算符允许我们组合 wueries 以保持干燥:
@container bubble style(--arrow-position: start start) or style(--arrow-position: end start) {
.bubble::after {
border-block-end-color: inherit;
inset-block-end: 100%;
}
}
/* is the same as... */
@container bubble style(--arrow-position: start start) {
/* etc. */
}
@container bubble style(--arrow-position: end start) {
/* etc. */
}
切换样式
容器样式查询和 正在做的工作是定义一个 toggle()
功能. 例如,我们可以循环两个 font-style
价值观,说 italic
和 normal
:
em, i, q {
font-style: italic;
}
@container style(font-style: italic) {
em, i, q {
font-style: normal;
}
}
凉爽的。 但是 CSS Toggles 的提议表明 toggle()
功能将是一个更简单的方法:
em, i, q {
font-style: toggle(italic, normal);
}
但是除了这种二进制用例之外的任何东西都在哪里 toggle()
不太适合。 不过,样式查询很好用。 Miriam 确定了三种样式查询比 toggle()
:
/* When font-style is italic, apply background color. */
/* Toggles can only handle one property at a time. */
@container style(font-style: italic) {
em, i, q {
background: lightpink;
}
}
/* When font-style is italic and --color-mode equals light */
/* Toggles can only evaluate one condition at a time */
@container style((font-style: italic) and (--color-mode: light)) {
em, i, q {
background: lightpink;
}
}
/* Apply the same query condition to multiple properties */
/* Toggles have to set each one individually as separate toggles */
@container style(font-style: italic) {
em, i, q {
/* clipped gradient text */
background: var(--feature-gradient);
background-clip: text;
box-decoration-break: clone;
color: transparent;
text-shadow: none;
}
}
样式查询解决了“Custom Property Toggle Hack”
请注意,样式查询是 “CSS 自定义属性切换技巧”. 在那里,我们设置了一个空的自定义属性(--foo: ;
) 并使用逗号分隔的回退方法在自定义属性设置为实际值时“切换”属性的打开和关闭。
button {
--is-raised: ; /* off by default */
border: 1px solid var(--is-raised, rgb(0 0 0 / 0.1));
box-shadow: var(
--is-raised,
0 1px hsl(0 0% 100% / 0.8) inset,
0 0.1em 0.1em -0.1em rgb(0 0 0 / 0.2)
);
text-shadow: var(--is-raised, 0 -1px 1px rgb(0 0 0 / 0.3));
}
button:active {
box-shadow: var(--is-raised, 0 1px 0.2em black inset);
}
#foo {
--is-raised: initial; /* turned on, all fallbacks take effect. */
}
这太酷了,样式容器查询也使很多工作变得微不足道。
样式查询和 CSS 生成的内容
对于由 content
的财产 ::before
和 ::after
伪元素,匹配容器是在其上生成内容的元素。
.bubble {
--arrow-position: end end;
container: bubble;
border: medium solid green;
position: relative;
}
.bubble::after {
content: "";
border: 1em solid transparent;
position: absolute;
}
@container bubble style(--arrow-position: end end) {
.bubble::after {
border-block-start-color: inherit;
inset-block-start: 100%;
inset-inline-end: 1em;
}
}
样式查询和 Web 组件
我们可以将一个web component定义为一个容器,通过style进行查询。 首先,我们有 组件的:
…
…
…
然后我们使用 :host
伪元素作为容器来设置 container-name
,以 container-type
,以及上面的一些高级属性:
:host {
container: media-host / inline-size;
--media-location: before;
--media-style: square;
--theme: light;
}
里面的元素 可以查询的参数
元件:
@container media-host style(--media-style: round) {
[part='img'] {
border-radius: 100%;
}
}
下一步是什么?
同样,我在这里记下的所有内容都是基于 Miriam 的笔记,这些笔记不能替代官方规范。 但它们表明正在讨论的内容以及未来可能发生的事情。 我感谢 Miriam 将一些仍在进行中的杰出讨论联系起来,我们可以关注这些讨论以掌握最新情况: