一、前言
本文的核心观点:适合自己的才是最好的!
本文将从css不同侧重点的类库及实现原理探索css工程化相关技术方案,比对其优劣点,旨在希望给各位在提升开发效率、制定css编码规范提供一些思路。
开始之前,我们先思考下下面三个问题:
1. 优秀CSS工程化技术方案的标准是什么?
2. CSS工程化要解决什么问题?
3. 不同的维度,你知道几种CSS工程化方案?
4. 你认为的最佳技术CSS工程化技术方案是什么?
好了,进入正题。下面文章围绕上面三个问题进行一一说明,我们开始吧!
二、CSS工程化标准是啥?
- 提升单人及协同开发效率。
- 方便扩展。
- 方便维护。
- 方便调试。
- 简单易用。
三、CSS工程化要解决什么问题
- 单人及协同开发效率问题。
- 业务扩展,需要样式表扩充以兼容需求。
- 新人加入,快速上手。老旧业务,方便维护。
- 方便调试,便于新人快速聚焦业务组件,梳理业务逻辑。
- 样式隔离:类名命名冲突时,由于css优先级会产生样式覆盖的问题。
- 简单易用易上手。
四、CSS工程化方案都有啥?
从js三剑客
的维度来讲,css工程化有3种方案,分别是:
-
- 以CSS预处理器
Sass/Less
+ CSS后处理器Postcss
为代表的纯CSS侧
方案。
- 以CSS预处理器
-
- 以TailWind.css为代表的以写辅助类为主的纯
HTML侧
方案。
- 以TailWind.css为代表的以写辅助类为主的纯
-
- 以styled-components、emotion 为代表的
CSS-in-JS侧
纯方案。它是针对React设计的一套css-in-js框架,当定义一个组件样式时,相当于创建了一个react组件。
- 以styled-components、emotion 为代表的
1. 方案优劣分析
方案 | 优点 | 不足 |
---|---|---|
CSS侧方案 | 可以使用预处理语言的高级语法。结合BEM规范、css-modules可以解决样式隔离问题。 | BEM规范是一种约定,如果不遵守就会失控。css-modules通过给class类名增加hash戳以解决样式冲突,做到了js和css分离,不过这可能导致BEM规范下部分SCSS如@mixin的高级预发无法发挥它的作用。 |
HTML侧方案 | 1.使用TailWind提供的辅助类结合style行内样式。 2.可以解决样式冲突问题 | 1.多个class类名才能达到一个样式目的,不易维护。 2.行内样式优先级太高,不推荐大规模使用。Redium一个优秀的行内样式库。 |
CSS-in-JS侧方案 | 官方推荐,能够优雅解决样式冲突问题 | 1.js中写css,违背js css分离原则。2.对css预处理器不友好。3.不利于调试,不能看到原始类名。 |
工作中,我们往往是取各方精华,多种方案配合使用,即能解决样式隔离等痛点,又能满足开发效率需要。
2. 各方案实际效果
1)CSS-Modules
CSS Modules 并不是 CSS 官方的标准,也不是浏览器的特性,而是使用一些构建工具,比如 webpack
,对 CSS
类名和选择器限定作用域的一种方式(类似命名空间)。原理是通过hash,使得类名唯一。
{
loader: 'css-loader',
options: {
modules: true, // 开启模块化
localIdentName: '[path][name]-[local]-[hash:base64:5]' // 类名名称
}
}
localIdentName的参数:
- [path] 表示样式文件相对于项目根目录所在的路径
- [name] 表示样式文件名称
- [local] 表示类名定义名称
- [hash:length] 表示32位的hash值。注意:只有类名选择器和 ID 选择器才会被模块化控制,标签选择器是不会被模块化控制。
2)CSS-in-JS
3) Tailwind.css
五、我认为的CSS工程化方案最佳实践 - scoped style
4. scoped style
类似于 vue 的scoped,局部作用域样式。
原理:通过给dom增加唯一自定义属性,借助CSS属性选择器,实现样式表对应关系及样式隔离。
优点:
- html、css、js分离原则。
- 和scss完美配合,可以自由使用sass的高级语法为所欲为。
效果如下:
使用方式:借助一个插件craco-plugin-scoped-css
yarn add craco-plugin-scoped-css
创建一个craco.config.js
文件:
module.exports = {
plugins: [
{
plugin: require('craco-plugin-scoped-css')
}
]
}
再来个babel插件
yarn add babel-plugin-react-scoped-css --dev
.babelrc中增加
"plugins": ["babel-plugin-react-scoped-css"]
webpack loader
yarn add scoped-css-loader --dev
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [require('tailwindcss'), require('autoprefixer')],
},
},
{ loader: 'scoped-css-loader' }, // 在这里
{
loader: 'sass-loader',
options: {
sourceMap: true,
prependData: `
@import "~ddo-assets/styles/mixin.scss";
@import "~ddo-assets/styles/bemMixin.scss";
@import "~ddo-assets/styles/_variables.scss";
`
},
},
],
},
实现原理图示:
对于内联元素处理
至于你喜欢哪一种,看你自己的心情~