众所周知,CSS 根据选择器名称去全局匹配元素,它没有作用域可言,比如你在页面的两个不同的地方使用了一个相同的类名,先定义的样式就会被覆盖掉。CSS 一直缺乏模块化的概念,命名冲突的问题会持续困扰着你。每次定义选择器名称时,总会顾及其他文件中是否也使用了相同的命名,这种影响在组件开发中尤为明显。(mp.weixin.qq.com/s/v0IB2mZHr…
相对应的就诞生了几种解决方案:
- CSS 命名方法论:通过人工的方式来约定命名规则
- CSS Modules:一个 CSS 文件就是一个独立的模块。
- CSS-in-JS:在 JS 中写 CSS。
CSS 命名方法论
共同的特点—为选择器增加冗长的前缀或后缀,并试图通过人工的方式来生成全局唯一的命名
.card {
&__head {}
&__menu {
&-item {
&--active {}
&--disable {}
}
}
&__body {}
&__foot {}
}
CSS Modules
基于上面这种手写命名前缀后缀的方式,诞生的css模块化方案
CSS Modules 允许我们像 import 一个 JS Module 一样去 import 一个 CSS Module。每一个 CSS 文件都是一个独立的模块,每一个类名都是该模块所导出对象的一个属性。通过这种方式,便可在使用时明确指定所引用的 CSS 样式。并且,CSS Modules 在打包时会自动将 id 和 class 混淆成全局唯一的 hash 值,从而避免发生命名冲突问题。(www.ruanyifeng.com/blog/2016/0…
CSS Modules 特性:
- 作用域:模块中的名称默认都属于本地作用域,定义在 :local 中的名称也属于本地作用域,定义在 :global 中的名称属于全局作用域,全局名称不会被编译成哈希字符串
- 命名:对于本地类名称,CSS Modules 建议使用 camelCase 方式来命名,这样会使 JS 文件更干净,即 styles.className
- 组合:使用 composes 属性来继承另一个选择器的样式
- 变量:使用 @value 来定义变量,不过需要安装 PostCSS 和 postcss-modules-values 插件。
CSS-in-JS
对于 HTML,衍生了 JSX 这种 JS 的语法扩展,可以将其理解为 HTML-in-JS;对于 CSS,衍生出一系列的第三方库,用来加强在 JS 中操作 CSS 的能力,它们被称为 CSS-in-JS。
Emotion:
- 不用关心繁琐的 Class 命名规则
- 不用担心样式被覆盖
- 便利的样式复用(样式都是 js 对象或字符串)
- 代码共享,轻松在 JS 和 CSS 之间共享常量和函数
- 组件化思考模式,不再需要维护一堆样式表。CSS-in-JS 将 CSS 模型抽象到组件级别,而不是文档级别(模块化)。
- Object Styles 和 String Styles
// yarn add @emotion/react @emotion/styled
// object styles
import { jsx } from '@emotion/react'
render(
<div
css={{
backgroundColor: 'hotpink',
'&:hover': {
color: 'lightgreen'
}
}}
>
This has a hotpink background.
</div>
)
// string styles
import { jsx, css } from '@emotion/react'
const paragraph = css`
color: turquoise;
a {
border-bottom: 1px solid currentColor;
cursor: pointer;
}
`
render(
<p css={paragraph}>
Some text.
<a>A link with a bottom border.</a>
</p>
)
- Styled Components 基础用法 Styled Components 导出了一些带有 html 标签的内置组件
import styled from '@emotion/styled'
let SomeComp = styled.div({
color: 'hotpink'
})
let AnotherComp = styled.div`
color: ${props => props.color};
`
render(
<SomeComp>
<AnotherComp color="green" />
</SomeComp>
)
// props 传递
import styled from '@emotion/styled'
const Button = styled.button`
color: ${props =>
props.primary ? 'hotpink' : 'turquoise'};
`
const Container = styled.div(props => ({
display: 'flex',
flexDirection: props.column && 'column'
}))
render(
<Container column>
<Button>This is a regular button.</Button>
<Button primary>This is a primary button.</Button>
</Container>
)
组件化做到了极致,自然形成了将HTML、CSS、JavaScript集中编写管理的方式
CSS Modules 与 styled-components 是两种截然不同的 CSS 模块化方案,它们最本质的区别是:前者是在外部管理 CSS,后者是在组件中管理 CSS。
扩展: 在 Vue 中编写 CSS 的姿势:使用 Scoped CSS,为 区块添加 scoped 属性即可开启组件样式作用域(Scoped CSS)
<template>
<header class="header">header</header>
</template>
<style scoped>
.header {
background-color: green;
}
</style>
// 编译之后
<header class="header" data-v-5298c6bf>header</header>
<style>
.header[data-v-5298c6bf] {
background-color: green;
}
</style>