@supports 谎言:当 CSS 说“是”,但浏览器说“LOL 不”。
Source: Dev.to
Introduction
根据 CSS 规范,@supports at‑rule 必须放在顶层或嵌套在另一个 conditional‑group at‑rule 中。然而,浏览器也允许如下代码(至少在理论上并不合法):
.my-class {
@supports (property: value) {
/* … */
}
}
这种行为令人困惑。浏览器要么完全忽略嵌套的 @supports(或者始终执行它,因为浏览器对 HTML 和 CSS 往往比较宽容),要么相对于它所在的规则来应用它。把它当作根级别规则来执行,却在视觉上嵌套在选择器内部,这会产生误导。
Example
li::marker {
@supports (content: " - ") {
content: " - ";
color: red;
}
}
- Chrome、Safari 和 Firefox 都支持
::marker,并且它们都支持content: " - "。 - Safari 不支持在
::marker中使用content。
使用上述代码时:
- Chrome 和 Firefox 会渲染出红色的 “ - ”。
- Safari 则渲染出一个红色的圆点。
令人困惑的是,@supports 条件会成功,即使该声明在特定上下文中实际上并不受支持。
Why This Happens
问题并不在于浏览器“移动”(更准确地说是“解析”)嵌套的 @supports 规则到顶层上下文,而在于 @supports 本身的定义。特性检查决定的是声明一般是否有效,而不是它在特定选择器或伪元素上下文中是否有效。
Possible Solutions
Extend @supports with Context‑Aware Checks
引入新的运算符或函数,使 @supports 能够验证组合而不是独立特性。例如:
@supports selector(::marker) and (content: " - ")
或
@supports selector(::marker) xand (content: " - ")
甚至是基于规则的检查:
@supports rule(::marker { content: " - " })
这些方式可以测试声明是否真的在给定的渲染上下文中起作用,而不仅仅是检查语法是否被识别。
Make Browsers Less Forgiving
一种不太理想的做法是让浏览器永不执行嵌套的 @supports 规则。但这会破坏依赖当前宽容行为的现有代码。
Workarounds
容器查询(container queries)和样式查询(style queries)有时可以作为变通方案,但它们目前仅部分支持,并且只能检查自定义属性,无法检查任意声明。虽然在某些情况下有帮助,但它们并未消除嵌套 @supports 带来的误导或局限性。