谈一谈在React项目中使用css-in-js方案

1、什么是css-in-js

参考:【css in js 简介】css

简单来讲,传统的前端方案推崇"关注点分离"原则,HTML、CSS、JavaScript 应该各司其职,进行分离。html

而在react项目中,更提倡组件化方案,天然造成了将HTML、CSS、JavaScript集中编写管理的方式。前端

开发方式由"关注点分离"变为了"关注点混合",成为了咱们在react中所熟悉的写法:node

const Widget = () => {
  <div style={{
      color: 'white',
      fontSize: '12px'
  }} onClick={() => doSometing()}>
    text  
  </div>
}
复制代码

可是这种写法的弊端在于,react中的style仅仅是简单的Object,不支持复杂的嵌套、选择器等特性,使用起来很不方便。 所以,便出现了大量的三方库来进行拓展,这些库统称为css-in-js。它们通常都支持样式嵌套、选择器、主题配置等特性。react

有人专门统计了现有的css-in-js三方库,轮子不要太多: css in js 三方库一览 。比较流行的主要有: styled-components, emotion, glamorous。git

尽管css-in-js带来许多好处,但仍有不足,在某些场景下使用仍然较繁琐。好比将繁琐的将css属性映射到props中的操做、使用theme时须要写很长的解析表达式(props => props.theme.colors.primary)等等。github

所以,除了这些css-in-js库以外,还有人基于它们作了更进一步的封装,提供了一些标准api来方便咱们更快速的使用css-in-js特性,好比:rebass,theme-ui。api

2、css-in-js 的使用

基于emotion举例bash

emotion的用法示例

emotion 官方文档antd

emotion 同时支持 css props写法和styled写法

1.string + css props 写法

import { css, jsx } from '@emotion/core'

const color = 'white'

render(
  <div
    css={css`
      padding: 32px;
      background-color: hotpink;
      font-size: 24px;
      border-radius: 4px;
      &:hover {
        background-color: ${color};
      }
    `}
  >
    Hover to change color.
  </div>
)
复制代码

2.object + css props写法

import { css, jsx } from '@emotion/core'

const color = 'white'

render(
  <div
    css={{
      padding: '32px',
      backgroundColor: 'hotpink',
      fontSize: '24px',
      borderRadius: '4px',
      '&:hover': {
        backgroundColor: color
      }
    }}
  >
    Hover to change color.
  </div>
)
复制代码

3.string + styled 写法

import styled from '@emotion/styled'

const color = 'white'

const Button = styled.div`
  padding: 32px;
  background-color: hotpink;
  font-size: 24px;
  border-radius: 4px;
  &:hover {
    background-color: ${color};
  }
`

render(<Button>This my button component.</Button>)
复制代码

4.object + styled 写法

import styled from '@emotion/styled'

const color = 'white'

const Button = styled.div(
    {
        padding: '32px',
        backgroundColor: 'hotpink',
        fontSize: '24px',
        borderRadius: '4px',
        '&:hover': {
          backgroundColor: color
        }
    }
)

render(<Button>This my button component.</Button>)
复制代码

能够看到,

  • string写法是纯粹的css样式,而object写法相似于react的style object,可是支持嵌套和selector。
  • css props写法能够直接将样式写在组建中,而styled写法是先将组件封装成一个新的组件后再使用。

更多特性,请查看官方文档,此文再也不赘述。

emotion 与 styled-components 如何选择

除了emotion以外,styled-components也比较经常使用

styled-components 官方文档

在使用上,styled-components 与 emotion 的styled写法同样,须要将组件封装成一个新的组件后再使用。

鉴于emotion已经支持了styled模式,能够优先选择emotion。

也能够参考theme-ui项目选择emotion的缘由:

While there are many different solutions to handling CSS in JavaScript, Styled Components and Emotion have become the most widely-used industry-standard libraries. If you're building a custom component library, either Styled Components or Emotion should suit your needs just fine.

For Theme UI, the decision was primarily based on these factors:

  • Emotion's implementation of the css prop and the custom JSX pragma allows for better integration with @styled-system/css
  • The Emotion API includes more lower-level utilities, like createEmotion that could be leveraged when considering how multiple themes could be composed together
  • Emotion's theming context is directly available in @emotion/core, allowing this library to leverage React's context API in different ways
  • In the case of Theme UI internals, the styled higher-order component utility is not necessarily the best API for creating components, and by not including @emotion/styled in the core package the bundle size is kept to a minimum – i.e. most of the same things can be achieved with the css prop

Emotion 的css props 写法、以及其提供的一些比较底层的api更利于自定义组件。而且在不适用styled风格的状况下,包体积更小。

3、Rebass:更进一步&开箱即用

rebass带来了什么

Rebass是基于styled-system、emotion、styled-components构建的一个可定制组件库。基于Rebass能够快速的构建符合项目风格的基础组件。

不一样于antd这类UI库,Rebass只提供几个原始的组件(Box、Flex、Text、Heading、Button、Link、Image、Card),这些组件都很是的初级,就像div同样。基于这些组件,以及Rebass的主题特性,咱们很容易就能够定制出项目用到的组件。

Rebass支持多种方式来编写组件样式:

  • sx props:基于reflexbox实现,相似于emotion中的object css prop,而且可以直接使用theme中定义的主题属性
  • style prop:基于styled-system实现
  • css prop:继承emotion的用法
  • styled:继承emotion的用法

几种用法举例:

// theme.js
export default {
    colors: {
        primary: 'red'
    },
    variants: {
        badge: {
          display: 'inline-block',
          p: 1,
          color: 'white',
          bg: 'primary',
          borderRadius: 2,
        }
      },
}
复制代码
// 1.sx prop
<Box variants="badge" sx={{
    bg: 'primary',
    height: '100px'
}}>
  <Text>123</Text>
</Box>

// 2.style prop
<Box variants="badge" bg='primary' height='100px'>
  <Text>123</Text>
</Box>
复制代码

从例子中能够看到:

  • 在rebass组件中咱们能够直接经过theme的key来使用主题样式,而不用写诸如props => props.theme.colors.primary之类的繁琐语句。
  • 咱们能够把css属性当作普通的prop传入组件(height),而不用作任何额外的操做。
  • 咱们能够经过variants来包裹一组css样式,使得主题具有了相似class的功能。这个是很是有用的一个功能,简化了主题样式的使用,并提升了可复用性。

rebass是如何作到的

Rebass库的源码很是少,主要是整合了reflexbox、styled-system以及styled-components的特性。

reflexbox

reflexbox文档

reflexbox基于Emotion和Styled Components实现,提供了两个具备响应式特性的组件:Box和Flex。除此之外,提供了sx prop特性来编写样式,遵循主题样式规范,完美支持主题定制。

能够说Rebass的主要特性所有由reflexbox实现,仅仅是在其之上作了一层封装,定制了几个基础组件,并提供了对styled-components的支持。

styled-system

styled-system 官方文档

Styled System is a collection of utility functions that add style props to your React components and allows you to control styles based on a global theme object with typographic scales, colors, and layout properties.

Styled System 提供了一系列工具方法来给React组件添加样式属性,而且支持使用全局样式来控制组件的尺寸、颜色和布局等属性。

很差理解?能够看一个简答的例子,咱们有一个白色组件,常规写法以下:

.white-block {
  color: '#fff'
}

<Compnent className="white-block"/>
复制代码

经过styled-system包装后,能够把color做为一个props放入组件中。相似于给html element增长自定义标签。

// 定义组件
import styled from '@emotion/styled'
import { color } from 'styled-system'

const Compnent = styled.div`
  ${color}
`

export default Compnent

// 使用组件,这里包装后不只提供了color属性,也提供了bg(background-color)属性
<Compnent color='#fff' bg='red'/>
复制代码

这就是文档中提到的:

Styled System is a collection of utility functions that add style props to your React components

styled-system 是如何工做的

官方说明连接

继续上面的例子,${color} 里面有什么魔法? 实际上,从styled-system导入的color是一个相似于这样的函数

props => `color: ${props.color}; background-color: ${props.bg}`
复制代码

正如描述中所说,styled-system就是帮咱们把css归类,并包装成了一些能够在emotion或者styled-components这类css-in-js库中使用的工具方法,方便咱们使用。

4、结语

除了文章中介绍的内容外,css-in-js还支持许多好用的特性,好比响应式布局选择器动画等等。

若是想体验css-in-js,能够先试试Emotion,了解一些基本的原理,而后直接上Rebass吧,用起来仍是挺香的。

欢迎留言交流~


关于咱们

深圳市浅海科技有限公司

咱们是一个高效、热情、有责任的技术团队,承接各类软件系统定制需求。

长期招聘远程开发者,若是您喜欢尝试新技术,有一点代码洁癖,可以使用文档进行高效的沟通,React/nodejs/ES6任意一种玩的飞起,那么,欢迎来撩~(想赚快钱的请绕道,谢谢)

简历请发送到:service@qianhaikeji.cn

固然,也欢迎甲方爸爸把项目甩咱们脸上。

相关文章
相关标签/搜索