难不成是因为天下大势,分久必合,合久必分?

传统前端推崇的“关注点分离”原则,推荐将 HTML、CSS、JavaScript 分离,各司其职。但是随着 React“组件化”思想的推进,已经将 HTML 用 JSX 的形式与 JavaScript 文件整合在一起,CSS 也可以通过以下写法同样的放入一个文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const Component = () => (
  <div
    style={{
      color: "white",
      fontSize: "12px",
    }}
    onClick={handleClick}
  >
    text
  </div>
);

但是这样写不支持复杂的嵌套、选择器等特性,使用起来不太方便。这里介绍几个 css-in-js 的库和一些基本用法!

styled-component

基本用法: codeSandbox

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import React from "react";
import Styled from "styled-components";

const Button = Styled.a`
  border-radius: 3px
  // ...
`;

function App() {
  return <Button>Learn React</Button>;
}

模板字符串也可以用 object 代替:

1
2
3
4
const Button = Styled.a({
  borderRadius: "3px",
  // ...
});

使用模板字符串或者传入 object 来生成一个组件,直接使用便可。

全局样式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import { createGlobalStyle } from "styled-components";
const GlobalStyle = createGlobalStyle`
  div {
    margin: 20px
  }
`;

return (
  <>
    <GlobalStyle />
    <div>
      <h3> initial button </h3>
    </div>
  </>
);

emotion

基本用法: codeSandbox

1
2
3
4
5
6
7
8
9
/** @jsx jsx */
import { jsx } from "@emotion/core";

const baseBtn = {
  borderRadius: "3px",
  // ...
};

return <button css={baseBtn}>Learn React</button>;

emotion 支持给 css 属性传入 object 格式的样式数据,但是想生效需要遵循以下两种方法其一:

  • 可以自定义 babelrc 文件的,引入一个 babel preset:
1
2
3
4
// .babelrc
{
  "presets": ["@emotion/babel-preset-css-prop"]
}
  • 不可以自定义 babelrc 的,(如使用了create-react-app)可以引入一个注释:
1
2
/** @jsx jsx */ // 对,就是这个
import { jsx } from "@emotion/core";

两种途径都是一个目的,用 emotion 的jsx方法来解析 jsx 而不是用React.createElement

css 属性也可以用模板字符串:

1
2
3
4
5
6
7
8
9
/** @jsx jsx */
import { jsx, css } from "@emotion/core";

const baseBtnWithTag = css`
  border-radius: 3px;
  // ...
`;

return <button css={baseBtnWithTag}>Learn React</button>;

还可以用类似 styled-components 的方法(模板字符串或者 object 都可以):

1
2
3
4
5
6
7
8
import styled from "@emotion/styled";

const Button = styled.a`
  border-radius: 3px;
  // ...
`;

return <Button>Learn React</Button>;

全局样式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { jsx, css, Global } from "@emotion/core";
const global = {
  div: {
    margin: "20px",
  },
};

return (
  <>
    <Global styles={css(global)} />
    <div>
      <h3> initial button </h3>
    </div>
  </>
);

// 或者是

return (
  <>
    <Global
      styles={css`
        div {
          margin: 20px;
        }
      `}
    />
    <div>
      <h3> initial button </h3>
    </div>
  </>
);

为什么同样的样式规则,展示出来的却不一样呢!

自我感觉是因为1em是相对根元素的尺寸,用 css 属性注入的样式保留了浏览器给 button 的原生样式,但是生成新 Button 的方法没有保留,所以他们相对的根元素是不一样的,样式就不一样啦!

jss

基本用法:codeSandbox

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import jss from "jss";
import preset from "jss-preset-default";

jss.setup(preset());

const styles = {
  button: {
    borderRadius: "3px",
    // ...
  },
};

function App() {
  const { classes } = jss.createStyleSheet(styles).attach();
  return <button className={classes.button} />;
}

全局样式:

1
2
3
4
5
6
7
const styles = {
  "@global": {
    div: {
      margin: "20px",
    },
  },
};

别的资料