React CSS-In-JS 方案 : Linaria Vs Styled-Components
在開發一個 React 應用時,其中一個比較大的挑戰就是為應用選擇一個合適的樣式處理方案。因為我們需要考慮到樣式的可維護性,開發體驗,以及樣式對應用效能的影響等。基於這些考慮,很多開發者會選擇使用 CSS-in-JS 方案。CSS-in-JS 方案將 javascript 作用於編寫應用樣式上。這有利於提升樣式的可維護性,在編寫樣式過程中使用更加模組化的方式,將「動態樣式」引入 react 應用中。目前市面上有非常多的 CSS-in-JS 方案。本文選擇了使用比較多的兩個方案 Linaria 和 Styled-components 進行比較
在本文中,我們將回顧這兩個流行的 CSS-in-JS 方案: Linaria 和 Styled-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
; ```
- 它也提供可以建立元素的 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; ```- 它通過 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
export default App; ```
其他的功能包括:
- 通過 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; ```
- 樣式擴充套件: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
export default App; ```
其他的功能,包括:
- 維護成本低
- 更簡便的刪除不必要的 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 體積的增加
我們可以從下面的資料中看到更多關於載入的對比
- http://github.com/geeky-biz/css-in-js-benchmark?ref=reactjsexample.com#page-loading-performance
- http://pustelto.com/blog/css-vs-css-in-js-perf/#lighthouse-performance-audit
基於渲染和使用者互動的效能對比
在這個方面的對比,主要是頁面元素拖拽互動以及重新渲染;結果顯示大部分的 Linaria 會有更少的指令碼執行時間,更少的樣式重繪重排
我們可以從下面的資料中看到更多關於渲染的對比
- http://github.com/geeky-biz/css-in-js-benchmark?ref=reactjsexample.com#re-rendering-performance
- http://pustelto.com/blog/css-vs-css-in-js-perf/#comparing-user-interaction
生態系統
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 的使用。然後又對比兩者之間的功能,效能特點以及生態系統。
本文的程式碼地址: