原生 CSS 嵌套(Native CSS nesting)已经被所有现代桌面浏览器所支持!,但是请注意,移动端浏览器支持的还很有限。
原生 CSS 嵌套可以像 SASS、LESS 预处理器一样,将相关的选择器组合在一起,从而减少需要编写的规则数量,它可以节省打字时间,并使语法更易于阅读和维护。您可以将选择器嵌套到任意深度,但要小心不要超过两层或三层。嵌套深度没有技术限制,但它会使代码更难以阅读,并且生成的 CSS 可能会变得不必要的冗长。
.button { background-color: red; &.warning { background-color: blue; } & .icon { width: 1rem; height: 1rem; }}
虽然原生 CSS 嵌套语法在过去几年中不断发展,使大多数 Web 开发人员感到满意,但不要指望所有 SCSS 代码都能像您期望的那样直接工作。
您可以将任何选择器嵌套在另一个选择器中,但它必须以符号开头,例如 &, .(类选择器)、#(ID选择器)、@(对于媒体查询)、:、::、+、 ~、 > 或 [。换句话说,它不能是对 HTML 元素的直接引用。下面的代码是无效的,不会对 input 元素选择器进行解析:
.parent { color: red; input { margin: 1em; }}/* Invalid, because "input" is an identifier. */
解决此问题的最简单方法是使用与号 ( &),它以与 Sass 相同的方式引用当前选择器。
.parent { color: red; & input { margin: 1em; } /* use pseudo-elements and pseudo-classes */ &::after {} &:hover {} &:target {}}/* valid, no longer starts with an identifier */
或者,您可以使用其中之一:
它们都可以在这个简单的示例中工作,但是稍后您可能会遇到更复杂的样式表的特异性问题。
它还&允许您在父选择器上定位伪元素和伪类。例如:
p.my-element { &::after {} &:hover {} &:target {}}
请注意,& 可以在选择器中的任何位置使用。例如:
.child1 { .parent3 & { color: red; }}
这将转换为以下非嵌套语法:
.parent3 .child1 { color: red; }
您甚至可以在选择器中使用多个 & 符号:
ul { & li & { color: blue; }}
这将以嵌套 <ul> 元素 ( ul li ul) 为目标,但如果您想保持理智,我建议不要使用它!
嵌套媒体查询示例:
p { color: cyan; @media (min-width: 800px) { color: purple; }}
原生 CSS 嵌套将父选择器包装在 :is() 中,这可能会导致与 Sass 输出的差异,比如以下嵌套代码:
.parent1, #parent2 { .child1 { }}
当它在浏览器中解析时,它实际上变成以下内容:
:is(.parent1, #parent2) .child1 {}
Sass 将相同的代码编译为:
.parent1 .child1,#parent2 .child1 {}
您可能还会遇到一个更微妙的问题。考虑一下:
.parent .child { .grandparent & {}}
原生 CSS 等效项是:
.grandparent :is(.parent .child) {}
这与以下错误排序的 HTML 元素匹配:
<div class="parent"> <div class="grandparent"> <div class="child">MATCH</div> </div></div>
MATCH变得有样式是因为 CSS 解析器执行以下操作:
它会查找所有元素,其所属类的child祖先也parent为DOM 层次结构中的任何点。
找到包含MATCH的元素后,解析器会grandparent在 DOM 层次结构中的任何位置再次检查它是否具有 — 的祖先。它找到一个并相应地设置该元素的样式。
Sass 中的情况并非如此,它编译为:
.grandparent .parent .child {} 上面的 HTML 没有样式化,因为元素类不遵循严格的grandparent、parent、 和child顺序。
Sass 使用字符串替换,因此如下所示的声明是有效的,并且与类的任何元素相匹配 .btn-primary:
.btn { &-primary { color: blue; }}
但是原生 CSS 嵌套会忽略&-space选择器。
从短期来看,现有的 CSS 预处理器仍然至关重要。Sass 开发团队宣布,他们将支持 .css 文件中的原生 CSS 嵌套,并按原样输出代码。他们将一如既往地编译嵌套 SCSS 代码,以避免破坏现有代码库,但当全球浏览器支持率达到 98% 时,他们将开始输出 :is() 选择器。
我猜想,PostCSS 插件等预处理器目前会扩展嵌套代码,但随着浏览器支持的普及,就会取消这一功能。当然,使用预处理器还有其他很好的理由,比如将部分代码捆绑到一个文件中,以及对代码进行精简。但如果嵌套是你唯一需要的功能,你当然可以考虑在较小的项目中使用原生 CSS。
CSS 嵌套是最有用、最实用的预处理器功能之一。浏览器供应商努力创造了一个与 CSS 非常相似的原生 CSS 版本,以满足网络开发人员的需求。虽然两者之间存在细微差别,而且在使用(过于)复杂的选择器时可能会遇到不寻常的特殊性问题,但很少有代码库需要进行彻底修改。
原生嵌套可能会让你重新考虑是否需要 CSS 预处理器,但它们仍能提供其他好处。Sass 和类似工具仍然是大多数开发者工具包的重要组成部分。