背景
在原生的CSS中,存在很多痛点需要优化:
- 语法简陋:没有变量、函数等高级特性
- 全局作用域污染:类名是全局通用的,很容易冲突
- 选择器规则复杂,难以维护,过长还可能导致CSS性能问题
- 样式的复用性差
- 样式生效有一些隐式规则:比如样式的继承规则、类名声明的先后顺序等都会影响最终的样式
优化方案
由于这些痛点的存在,导致CSS的开发效率低下,维护成本也比较高。
统一类名的命名规则
BEM(Block Element Modifier)命名规则 根据该命名规则,样式类名的命名方式是:block__element--modifier.
- block:块 功能模块的名称,比如一个按钮
.btn - element:元素 块的组合部分,一般是元素的功能,比如下拉元素
.block__dropdown - modifier:修饰符,一般是元素的状态,比如禁用状态
.block__dropdown--disabled
通过该命名规则,可以为不同功能的元素和状态定义不同的样式类名,从而提高代码的可维护性。
缺点
- 类名的命名规则比较复杂,需要记忆
- 依靠开发者来维护, 需要成本并且容易出错
CSS预处理器
Scss以及Less等CSS预处理器可以提供一些高级特性,比如变量、函数、嵌套等,可以提高代码的可维护性。
缺点
- 并不是原生的,需要经过处理编译之后才能在浏览器中生效,增加了成本
- 需要学习新的语法
CSS后处理器
PostCSS是典型的CSS后处理器,对已有的CSS进行处理。可以提供一些高级特性,比如自动添加浏览器兼容前缀、自动添加单位、CSS代码压缩等。
缺点
- 也需要额外的学习成本,并且需要配置才能生效
- 外搭的,也会增加构建成本
原子化CSS
代表工具就是TailwindCSS,通过预定义的类名来细粒度的控制CSS样式,进而提高CSS开发效率,从根本上避免了样式冲突。
缺点
- 预定义的类名比较多,需要记忆,增加了学习成本
- 类名可能过长,对代码的可读性有一定影响
- 复杂的动画等是不能满足的
CSS in JS
CSS in JS是通过JS来编写CSS样式,然后将动态生成的CSS样式注入到HTML的style标签中。并且通过复用JS的作用域,增强了CSS的能力。
代表工具是styled-components以及emotion.js。
styled-components为例,动态生成的CSS样式是不固定的,通过hash来生成唯一的类名,从而避免了样式冲突。
缺点
- 动态生成的CSS,所以会有一些性能开销
- 组件内使用的话,生成的类名不固定,复用时难以控制内部样式
CSS in JS Props方案
借助Babel等编译工具,直接在JSX的css属性上添加样式,然后再编译成CSS。
但是这种方式本质还是CSS in JS,所以缺点还是一样的。
CSS Module
CSS Module是通过CSS预处理器来实现的,通过CSS Module可以将CSS样式封装到一个模块文件(通常是xxx.module.less)中,从而避免了样式冲突。
缺点
- 需要添加额外的配置来控制生成的类名。
- 对于组件来说,内部的类名也是难以复用的,因为类名一般都是根据路径来动态生成的。