談一談在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

固然,也歡迎甲方爸爸把項目甩咱們臉上。

相關文章
相關標籤/搜索