传统Css的缺陷
1. 缺乏模块组织
传统的 JS 和 CSS 都没有模块的概念,后来在 JS 界陆续有了 CommonJS 和 ECMAScript Module,CSS-in-JS 可以用模块化的方式组织 CSS,依托于 JS 的模块化方案,比如:
import styled from '@emotion/styled'
export const Button = styled.button`
color: turquoise;
`
2. 缺乏作用域
传统的 CSS 只有一个全局作用域,比如说一个 class 可以匹配全局的任意元素。随着项目成长,CSS 会变得越来越难以组织,从此导致类名冲突, 样式冲突。CSS-in-JS 可以通过生成独特的选择符,来实现作用域的效果:
const css = styleBlock => {
const className = someHash(styleBlock);
const styleEl = document.createElement('style');
styleEl.textContent = `
.${className} {
${styleBlock}
}
`;
document.head.appendChild(styleEl);
return className;
};
const className = css(`
color: red;
padding: 20px;
`); // 'c23j4'
3. 隐式依赖, 让样式难以追踪
比如这个css样式:
.target .name h1 {
color: red
}
body #container h1 {
color: green
}
<!doctype html>
<html lang="en">
<body>
<div id='container'>
<div class='target'>
<div class='name'>
<h1>我是啥颜色?</h1>
</div>
</div>
</div>
</body>
</html>
那么这个 h1 元素最终显式为什么颜色?加入你想要追踪这个影响这个 h1 的样式,怎么追踪?
而 CSS-in-JS 的方案就简单直接、易于追踪:
export const Title = styled.h1`
color: green;
`
<Title>
我是啥颜色?
</Title>
4. 没有变量
传统的 CSS 规则里没有变量,但是在 CSS-in-JS 中可以方便地控制变量:
const Container = styled.div(props => ({
display: 'flex',
flexDirection: props.column && 'column'
}))
5. Css选择器与HTML元素耦合
.target .name h1 {
color: red
}
body #container h1 {
color: green
}
<!doctype html>
<html lang="en">
<body>
<div id='container'>
<div class='target'>
<div class='name'>
<h1>我是啥颜色?</h1>
</div>
</div>
</div>
</body>
</html>
如果你想把 h1 改成 h2,必须要同时改动 CSS 和 HTML。而在 CSS-in-JS 中,HTML 和 CSS 是结合在一起的,易于修改。
Emotion 介绍
Emotion 是目前最受欢迎的 CSS-in-JS 库之一,它还对 React 作了很好的适应,可以方便地创建 styled component,也支持写行内样式:
/** @jsx jsx */
import { jsx } from '@emotion/react'
render(
<div
css={{
backgroundColor: 'hotpink',
'&:hover': {
color: 'lightgreen'
}
}}
>
This has a hotpink background.
</div>
)
这种写法比起 React 自带的 style 的写法功能更强大,比如可以处理级联、伪类等 style 处理的不了的情况:
<span style={{ color: "red" }}>{keyword}</span>