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

  1. 传统的js和css都没有模块的概念,后来在js界陆续有了CommonJS和ES 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-1c4ktv6 > * {
    margin-top: 0;
    margin-bottom: 0;
}

使用someHash函数生成一个独特的className

const css = styledBlock => {
    const className = someHash(styledBlock);
    const styleEl = document.createElement('style');
    styleEl.textContent = `
        .${className} {
            ${styleBlock}
        }
    `;
    document.head.appendChild(styleEl);
    return className;
}
// 使用
const className = css(`
    color: red;
    padding: 20px
`)
  1. 隐式依赖, 样式难以追踪
.target .name h1 {
    color: red;
}
body #container h1 {
    color: green;
}

这个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;
}

如果有一天我们想要把h1改成h2,必须要同时改动css和html,而在CSS-in-JS中,HTML和CSS是结合在一起的,易于修改。

export const Title = styled.h1`
    color: green;
`
<Title>文字颜色</Title>

export const Title = styled.div`
    color: green;
`

Emotion

Emotion是目前最受欢迎的CSS-in-JS库之一,他还对React做了很好的适应,可以方便的创建styled component也支持写行内样式。

import { jsx } from '@emotion/react'

render(
    <div
        css={{
            backgroundColor: 'hotpink',
            '&.hover': {
                color: 'lightgreen'
            }
        }}
    >
        background
    </div>
)

这种写法比起React自带的style的写法功能更强大,比如可以处理级联,伪类等style处理不了的情况。

安装和使用Emotion

yarn add @emotion/react @emotion/styled

可以给编辑器安装一个高亮语法插件,styled.component

import styled from '@emotion/styled'
import Card from '....';

const Container = styled.div`
    display: flex;
    flexDirection: column;
    aligin-items: center;
    min-hieght: 100vh;
`

// 普通React的组件来使用
<Container>
    <ShadowCard></ShadowCard>
</Container>

需要注意的是styled后面跟的属性必须是html的标签对象,如果想要将样式属性给到组件,需要使用()调用。

const ShadowCard = styled(Card)`
    display: flex;
    flexDirection: column;
    aligin-items: center;
    min-hieght: 100vh;
`

可以通过as属性将标签改变,比如下面的抱歉原本为div,可以使用as改为h3

const Container = styled.div`
    color: red;
`

// 普通React的组件来使用
<Container as={'h3'}>
    123
</Container>

可以定义组件样式

export const Row = styled.div<{
    gap?: number | boolean,
}>```
marginTop: ${props.gap}px;

```