提醒:本文最后更新于 2019/11/18 ,文中所描述的信息可能已发生改变,请谨慎使用。

一个 ng 项目,今天做 code review 的时候,发现了一个问题,同事写的 scss 代码里面有大量嵌套结构的后代选择器。于是引出这篇小文章,9102年了,你为啥还大量用嵌套结构写样式。

过去的 css

在早期,大型项目编写可维护的 css 代码还是很复杂的,据说腾讯 Qzone 团队还会专门有一个同学负责全局统一管理 z-index

全局作用域带来的命名冲突问题,衍生带来了一批 css 命名规范——例如 BEM,通过团队规范来保证 css 选择器对正确的元素生效。

当然,这些方案都是基于 css 选择器优先级来实现的,其中最常用的就是后代选择器了。

我们为了保证自己的样式仅对自己写的代码生效,我们都会写出这样的代码

.scope .selector1 {
}
.scope .selector1 .selector2 {
}
.scope p {
}

为什么要写嵌套结构

通过后代选择器,我们的确在一定程度上解决了 css 选择器命名冲突的问题。但是随之而来的就是代码量的膨胀,我们每写一个选择器,都需要在这个选择器前面加上一个另一个选择器来保证作用范围,作为会偷懒的程序员,我们为啥不发明一种新的格式来简化这种繁琐的复制粘贴咧。

于是乎 less stylus scss 等预编译的 css 方言出现了。而这些方言不约而同的都实现了选择器嵌套书写这种便捷的方式。

.scope {
  .selector1 {
    .selector2 {
    }
  }
  p {
  }
}

似乎这套方案有很正常地解决了程序员的难题若干年,直到 MVVM 的流行……

新技术选型下的替代方案

回到9102年,前端程序员不再是那个写 HTML+CSS+JS 然后把代码丢给后端填数据的切图仔了。Web Component 虽然没有大规模使用,但是各大主流前端框架和库把模块化都作为重要的一部分并提供了不同的解决方案。

react

styled-component,css module,均可作为 react 生态下的样式表模块化方案。

Angular

其官方生态下,对 css 样式表通过添加[scope]属性选择器实现了模块化。

Vue

与 Ng 类似的方案,可以通过参数手工指定是否模块化。

回头看

我们既然选择了主流的前端解决方案,我们为啥还要把前朝遗老搬过来用呢?

在新技术下,我们可以充分扁平 css 选择器,减少嵌套,一是带来更好的可维护性,二是节约键盘。

我们就像这样简单书写,搞定啦

.selector1 {
}
.selector2 {
}
p {
}

PS

当然,嵌套格式还是有他发挥作用的时候,毕竟存在即合理。

但是若你是用嵌套格式来处理上个世界的 css 命名冲突的问题,请把这些问题放心交给流行的前端解决方案吧。