Web 功能:
容器样式查询
问题
我们通常需要组合不同类型的过滤条件,例如选择器 + 媒体查询、媒体查询 + 容器查询等。
例如,将 (prefers-color-scheme: dark) 与定位到配色方案替换项的选择器(例如 :root:has(> head > meta[name="color-scheme"][content="dark"]) 或 :root.dark)结合使用,以便在浅色/深色模式下应用特定样式,而不管配色方案是如何设置的。
简单的方法会导致代码重复:
/* Light mode styles */
.card.featured {
font-weight: 400;
}
#logo-dark {
display: none;
}
@media (prefers-color-scheme: dark) {
/* Dark mode styles */
:root:not(.light) {
.card.featured {
font-weight: 300;
}
#logo-dark {
display: inline;
}
#logo {
display: none;
}
}
}
/* Dark mode styles, again */
:root.dark {
.card.featured {
font-weight: 300;
}
#logo-dark {
display: inline;
}
#logo {
display: none;
}
}
建议的做法
将组合过滤条件的结果存储在自定义属性中,然后使用容器样式查询根据该属性设置规则。
重要提示:由于容器查询的工作方式,只有当我们可以在必须匹配的任何规则的祖先上设置自定义属性时,此技术才有效。
1. 将选择逻辑与应用的规则解耦
:root {
--color-scheme: light;
@media (prefers-color-scheme: dark) {
--color-scheme: dark;
}
&:has(> head > meta[name="color-scheme"][content="dark"]) {
--color-scheme: dark;
}
&:has(> head > meta[name="color-scheme"][content="light"]) {
--color-scheme: light;
}
}
2. 所应用规则的自定义属性的键
@container not style(--color-scheme: dark) {
.card.featured {
font-weight: 400;
}
#logo-dark {
display: none;
}
}
@container style(--color-scheme: dark) {
.card.featured {
font-weight: 300;
}
#logo {
display: none;
}
}
3. 可选:用于切换可见性的实用程序类
一个非常常见的用例是根据条件是否匹配来切换可见性。
实用程序类必须优先于任意组件样式(因此使用 !important),并且其显示的 display 未知,因此无法使用替换项,请使用 not style(...) 进行控制:
@container not style(--color-scheme: dark) {
.if-dark {
display: none !important;
}
}
@container not style(--color-scheme: light) {
.if-light {
display: none !important;
}
}
后备
后备分为两种类型,具体取决于分支的重要程度以及可接受的后备内容。
- 对于关键分支,即使不支持样式查询,所有状态也必须正常运行,因此您根本无法使用样式查询。 而是应使用上述简单方法,为每个状态复制规则。 只要实用程序类也以这种方式定义,就仍然可以使用。
- 对于非关键分支(其中默认状态可接受),您可以在任何
@container规则之外定义基本样式,并且仅使用样式查询作为替换。 这保留了此方法的大部分精神,其主要缺点是覆盖引入的值的耦合。
#logo-dark {
display: none;
}
@container style(--color-scheme: dark) {
#logo-dark {
display: inline; /* override */
}
#logo {
display: none;
}
}