React CSS-In-JS 方案 : Linaria Vs Styled-Components

語言: CN / TW / HK

在開發一個 React 應用時,其中一個比較大的挑戰就是為應用選擇一個合適的樣式處理方案。因為我們需要考慮到樣式的可維護性,開發體驗,以及樣式對應用效能的影響等。基於這些考慮,很多開發者會選擇使用 CSS-in-JS 方案。CSS-in-JS 方案將 javascript 作用於編寫應用樣式上。這有利於提升樣式的可維護性,在編寫樣式過程中使用更加模組化的方式,將「動態樣式」引入 react 應用中。目前市面上有非常多的 CSS-in-JS 方案。本文選擇了使用比較多的兩個方案 LinariaStyled-components 進行比較

在本文中,我們將回顧這兩個流行的 CSS-in-JS 方案: LinariaStyled-components 。我們將一起研究他們的功能,同時比較他們功能差異,效能以及生態。

CSS-in-JS 解決方案

CSS-in-JS 解決方案給我們提供了新的編寫 CSS 的方式。這些方案使用以 javascript 為基礎的 API 來建立和編寫樣式。主要的優點包括:

  • 動態樣式:允許開發者編寫動態 CSS
  • 元素作用域:可以把樣式的範圍固定在某些元素上
  • 消除無用程式碼:會自動除去應用中冗餘的 CSS 程式碼
  • 支援自定義主題
  • 安裝和設定簡單
  • 支援 ES modules 和 作用域
  • 更加容易編寫單元測試
  • 效能提升
  • 支援 SSR
  • 支援所有的 CSS 語法

Linaria

Linaria 是最流行的 CSS-in-JS 解決方案之一,GitHub 擁有 7.1k 個 star 和 260 個 fork。Linaria 是 「零執行時」方法,這意味著它將開發者寫好的樣式程式碼在構建時轉換為一個單獨的 .css 檔案。這個行為跟很多的 CSS 前處理器相似,比如 SASS ,LESS

它提供了很多功能,包括:

  • 提供建立 CSS 類的 API 。”css” API 允許開發者建立所選擇的樣式,同時他也支援模版語法來滿足當我們需要插入動態值。

``` import { css } from '@linaria/core';

const red = "red" const header = csstext-transform: uppercase; color: ${red};

Hello world

; ```

0.png

  • 它也提供可以建立元素的 API. “styled” API 允許開發者建立任何元素,比如: div,p,等等。當然,這個 API 也是支援模版語法來插入對應的變數值的

``` import { styled } from '@linaria/react'

const Container = styled.div` font-size: 35px; color: red; border: 1px solid red;

&:hover { border-color: blue; }

h1 { margin-bottom: 24px; } `;

const App = () => { return

Hello World

} export default App; ```

1.png

  • 它通過 React 的 Props 或者常規變數來管理動態樣式。在下面的程式碼中,我們通過 React 元件傳遞 props 和一些常規變數到另一個元素上

``` import { styled } from '@linaria/react';

const Title = styled.h1font-family: inherit;; const medium = 30

const Navbar = styled.nav` font-size: ${medium}px; color: ${props => props.color}; border: 1px solid red;

&:hover { border-color: blue; }

${Title} { margin-bottom: 24px; } `;

const App = () => { return Hello world }

export default App; ```

2.png

其他的功能包括:

  • 通過 CSS source maps 可以很容易的找到樣式變數是在哪裡定義的
  • 可以在 JS 程式碼中開啟 CSS Lint http://github.com/stylelint/stylelint
  • 通過 @linaria/atomic 可以支援原子樣式

*Styled-Components*

Styled-Components 也是流行的 CSS-in-JS 解決方案之一。在 GitHub 上擁有 37.2 k 的 star 和 2.3 k 的 forks。Styled-components 讓開發者能夠通過編寫真實的 CSS 程式碼來修改元件的樣式。它在元件和樣式之間建立了一個抽象層,從而消除了直接的對映。

提供的能力,包括:

  • 自動提取關鍵 CSS 和 程式碼分割:Styled-Components 監控元件,並且在元件渲染到頁面的時候插入元件必要的樣式程式碼。同時支援程式碼分割來加快元件載入的速度
  • 為樣式生成唯一的類名,以防止樣式的覆蓋,拼寫錯誤以及冗餘
  • Styled-component 也提供通過 props 或者常規變數為元素注入動態值。“styled” API 允許開發者建立選擇的元素,跟 Linaria 一樣,Styled-component 也支援大致相同的模版語法

``` import styled from 'styled-components';

const Button = styled.button` background: ${props => props.primary ? "palevioletred" : "white"}; color: ${props => props.primary ? "white" : "palevioletred"};

font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid palevioletred; border-radius: 3px; `;

const App = () => { return

}

export default App; ```

3.png

  • 樣式擴充套件:Styled-Components 允許在已有的樣式上通過 styled 進行擴充套件

``` import styled from 'styled-components';

const Button = styled.buttoncolor: palevioletred; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid palevioletred; border-radius: 3px;;

const TomatoButton = styled(Button)color: tomato; border-color: tomato;;

const App = () => { return

Tomato Button
}

export default App; ```

3-1.png

4.png

其他的功能,包括:

  • 維護成本低
  • 更簡便的刪除不必要的 CSS
  • 支援 SSR
  • 支援主題定製

對比 Linaria 和 Styled-Components

開發者在很長一段時間都在選擇最適合自己專案的樣式解決方案,而 Linaria 和 Styled-Components 無疑是當中的佼佼者。接下來我們將從:「功能」,「效能」以及 「生態」來對這兩個方案進行比較

功能

  • Linaria 是「零執行時」方案,這意味著樣式檔案會在構建時被單獨抽取成 CSS 檔案;Styled-Components 則是在構建時通過 javascript 將 CSS 注入,不會生成額外的 CSS 檔案
  • 都擁有相似的 CSS 語法(類似 Sass 的風格)
  • 在 React 應用中都可以基於 Prop 實現變數注入(原理是使用 CSS 變數)
  • 都可以通過 CSS source maps 很快找到 CSS 變數定義的位置
  • 都可以通過 stylelint 的方案進行程式碼檢查
  • 都使用 Javascript 來組織程式碼邏輯,無需使用 CSS 前處理器
  • 都可以平替 Sass 或者 PostCSS 方案

通過上述的的功能描述,我們發現 Linaria 和 Styled-Components 的 API 都比較相似,所以開發者很容易就可以從其中一個方案遷移到另一個方案

基於請求的效能對比

  • 在生產環境中, Linaria 會產生額外的 .css 檔案,這將會引起 CSS 檔案體積變大,檔案數量變多,導致請求數量變多的問題
  • 對於 Styled-Components 來說,相同情況下,CSS 檔案體積和數量無疑是更少的,但是會增加 JS bundle 的體積大小

許多爭論在於認為 Linaria 產生的 css 檔案對效能的影響是比較小的,相對於 Styled-Components ,Linaria 不會增加 JS bundle 體積是一種更好的取捨;而另一些則認為 Linaria 增加了 CSS 冗餘程式碼的可能性。

我們可以在 這裡 看到更多關於請求的效能對比

基於頁面載入的效能對比

在加入多種頁面載入標準之後發現,大部分的頁面使用 Linaria 的載入效能要 好於 使用 Styled-Components。其中一個比較重要的原因就是,Linaria 導致的 CSS 資源體積與數量的增加對於頁面載入的影響要小於 Styled-Components 導致的 JS bundle 體積的增加

我們可以從下面的資料中看到更多關於載入的對比

基於渲染和使用者互動的效能對比

在這個方面的對比,主要是頁面元素拖拽互動以及重新渲染;結果顯示大部分的 Linaria 會有更少的指令碼執行時間,更少的樣式重繪重排

我們可以從下面的資料中看到更多關於渲染的對比

生態系統

Styled-components 目前擁有 37.2K GitHub stars, 2.3K GitHub forks,超過 4百萬的 NPM 包周下載量,可以說是 CSS-in-JS 最大的生態系統方案;而 Linaria 只有 7.1K GitHub stars, 260 GitHub fork 和 16000 的 NPM 包周下載量。這意味著 Styled-components 會有更大的社群以及討論熱度,更多的課程(學習成本低)以及更多的問題解答等等

總結

本文我們先介紹了 Linaria 和 Styled-Component 的使用。然後又對比兩者之間的功能,效能特點以及生態系統。

本文的程式碼地址:

參考資料