一、背景
css是前端人员的一种必备的技能,原生css不像编程语言一样可以通过复用等方式,往往会出现编写很多重复代码,以及选择器类名等是全局通用的,当所需要开发的项目比较小时,在类名的命名上可能是没有什么影响,但是当开发的项目有了一定的范围之后,将会遇上命名困难,样式冲突等问题,以及在css的维护上将会极其困难,可以说css代码像一座山一样,越堆越多。 为了解决这些困难,前端领域出现了一些各种各样的框架和方案。
二、关于css问题的框架和解决方案
目前列出的有如下解决方案: BEM、css module、css in js、Atomic css
三、关于以上四种css解决方案的讲解概括
1、BEM
BEM就是三个单词的缩写:Block(模块)、Element(元素)、Modifier(修饰符)
好的css取名规则可以让代码更容易阅读和维护
Block一个独立的实体,代表了更高级别的组件(block);
Element元素,抽象的说,就是block的后代,也就是子模块,用于形成一个完整的block整体(block__element);
Modife修饰符,block与element上的标志,用于来表示形容他们的属性、状态、行为等等(block--modifer)。
命名方式 .模块名__元素名--修饰器名
优势: a、识别度高、结构清晰,element 和 modifier 与 block 之间的从属关系,可以从名称上就一目了然的区分
b、隔离性好,每一个区块之间都有是一个独立的空间,减少与其他元素的污染。
c、良好的扩展性,因为modifier修饰符的存在,我们需要去添加别的样式的时候,只需要创建一个新的修饰符就行,例如 .btn-active, .btn-hidden
2、css module
CSS Modules 允许我们像 import 一个 JS Module 一样去 import 一个 CSS Module。每一个 CSS 文件都是一个独立的模块
CSS Module只是加入了局部作用域和模块依赖,可以保证某个组件的样式,不会影响到其他组件。
随着项目的越来越大,越来越难以维护,就容易导致命名的混乱。
css module可以保证我们类名的唯一性,解决css 全局污染、层次结构不清晰、代码难以复用等问题。
CSS Modules 在打包时会自动将 id 和 class 混淆成全局唯一的 hash 值,从而避免发生命名冲突问题。
CSS Modules 特性:
- 作用域:模块中的名称默认都属于本地作用域,定义在
:local中的名称也属于本地作用域,定义在:global中的名称属于全局作用域,全局名称不会被编译成哈希字符串。 - 命名:对于本地类名称,CSS Modules 建议使用 camelCase 方式来命名,这样会使 JS 文件更干净,即
styles.className。 但是你仍然可以固执己见地使用styles['class-name'],允许但不提倡。 - 组合:使用
composes属性来继承另一个选择器的样式,这与 Sass 的@extend规则类似。 - 变量:使用
@value来定义变量,不过需要安装 PostCSS 和 postcss-modules-values 插件。
/* style.css */
:global(.card) { padding: 20px; }
.article { background-color: #fff; }
.title { font-size: 18px; }
// App.js
import React from 'react'
import styles from './style.css'
export default function App() {
return ( <article className={styles.article}>
<h2 className={styles.title}>Hello World</h2>
<div className="card">Lorem ipsum dolor sit amet.</div>
</article> )
}
<style>
.card { padding: 20px; }
.style__article--ht21N { background-color: #fff; }
.style__title--3JCJR { font-size: 18px; }
</style>
<article class="style__article--ht21N">
<h2 class="style__title--3JCJR">Hello World</h2>
<div class="card">
test
</div>
</article>
css module的使用方式
//在 webpack 中使用 CSS Modules(开启 [css-loader] 的 modules 特性)
// webpack.config.js -> module.rules
{
test: /\.(c|sa|sc)ss$/i,
exclude: /node_modules/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2, // 开启 CSS Modules
modules: true, // 借助 CSS Modules,可以很方便地自动生成 BEM 风格的命名
localIdentName: '[path][name]__[local]--[hash:base64:5]',
},
},
'postcss-loader',
'sass-loader',
],
},
// 在 PostCSS 中使用 CSS Modules,需要泳道postcss-modules的插件
// postcss.config.js
module.exports = {
plugins: {
'postcss-modules': {
generateScopedName: '[path][name]__[local]--[hash:base64:5]',
},
},
}
、css in js
以前我们编写前端页面的方式一般都是一个文件写js代码加dom结构,一个文件写css,在js文件里引入css代码的文件,
css in js 的方式让我们可以实现在一个文件里,既包含了js代码,又包含了Dom, 还包含了css.
传统的方式 js + dom
css in js 的方式 js + dom + css
// styles.js
import styled, { css } from 'styled-components'
// 创建一个名为 Container 的样式组件 (一个 section 标签, 并带有一些样式)
export const Container = styled.section`
padding: 10px;
width: 100%;
height: 100vh;
background: #000;
`
//按照常规去使用该组件
export Index = () => {
return <Container><Container/>
}
列举一些流行的css in js 库
styled-components 是目前最流行的 CSS-in-JS 库,
emotion
Styled System
styled-jsx
JSS
4、Atomic css
Atomic 意思是原子的意思
Atomic CSS是CSS架构的一种方法, 它的好处是写出基于视觉功能的小的, 单用途CSS类.
使用Atomic CSS, 为每个可重用的属性创建单独的CSS类.
例如, margin-top: 1px;
就可以创建一个类似于mt-1的CSS类, 或者width: 200px; 对应的CSS类为w-200.
目前使用到的一个类似于该方案的css框架 ,tailwind。
优点:使用这种方式可以最大程度地减少CSS代码数量
缺点:css类名没有语义化,使开发人员无法通过class类名看懂该css功能作用