CSS-in-JS

摩森特沃 2021年07月06日 368次浏览

CSS-in-JS 不是指某一个具体的库,是指组织CSS代码的一种方式,代表库有 styled-component 和 emotion

传统CSS的缺陷

  1. 缺乏模块组织

传统的JS和CSS都没有模块的概念,后来在JS界陆续有了 CommonJS 和 ECMAScript Module,CSS-in-JS可以用模块化的方式组织CSS,依托于JS的模块化方案,比如:

// button1.ts
import styled from '@emotion/styled'

export const Button = styled.button`
  color: turquoise;
`
// button2.ts
import styled from '@emotion/styled'

export const Button = styled.button`
  font-size: 16px;
`
  1. 缺乏作用域

传统的CSS只有一个全局作用域,比如说一个class可以匹配全局的任意元素。随着项目成长,CSS会变得越来越难以组织,最终导致失控。CSS-in-JS可以通过生成独特的选择符,来实现作用域的效果

生成的css示例

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'
  1. 隐式依赖,让样式难以追踪

比如这个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>
  1. 没有变量

传统的CSS规则里没有变量,但是在 CSS-in-JS 中可以方便地控制变量

const Container = styled.div(props => ({
  display: 'flex',
  flexDirection: props.column && 'column'
}))
  1. 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>