CSS in JS (JSS)

辜負寒徹骨發表於2023-03-27

JSS 是什麼

簡單來說,一句話概括CSS in JS (JSS),就是"行內樣式"(inline style)和"行內指令碼"(inline script)。

因為,自從React出現以後,基於元件化的要求,強制把HTML、CSS、JavaScript捆綁在一起,在同一個檔案裡面,封裝了結構、樣式、以及邏輯。這雖然違背html發明初期的"關注點分離"的原則,但更有利於元件之間的隔離。而每個元件包含了所有需要用到的程式碼,不必依賴外部環境,元件之間沒有耦合。所以,隨著 React 的走紅和元件模式深入人心,“關注點分離”原則越發淡出人們的視野,而React所帶來的"關注點混合"的原則逐漸成為主流。[1]

React 對 CSS 封裝非常簡單,就是沿用了 DOM 的 style 屬性物件。CSS-in-JS是一種技術(technique),而不是一個具體的庫實現(library)。簡單來說CSS-in-JS就是將應用的CSS樣式寫在JavaScript檔案裡面,而不是獨立為一些.css,.scss或者less之類的檔案,這樣你就可以在CSS中使用一些屬於JS的諸如模組宣告,變數定義,函式呼叫和條件判斷等語言特性來提供靈活的可擴充套件的樣式定義。值得一提的是,雖然CSS-in-JS不是一種很新的技術,可是它在國內普及度好像並不是很高,它當初的出現是因為一些component-based的Web框架(例如React,Vue和Angular)的逐漸流行,使得開發者也想將元件的CSS樣式也一塊封裝到元件中去以解決原生CSS寫法的一系列問題。還有就是CSS-in-JS在React社群的熱度是最高的,這是因為React本身不會管使用者怎麼去為元件定義樣式的問題,而Vue和Angular都有屬於框架自己的一套定義樣式的方案。[2]

JSS 的常見實現

由於React 對 CSS 的封裝非常弱,導致出現了一系列的第三方庫,用來加強 React 的 CSS 操作。它們統稱為 CSS in JS,意思就是使用 JS 語言寫 CSS。根據不完全統計,各種 CSS in JS 的庫至少有47種。老實說,現在也看不出來,哪一個庫會變成主流。[1]

1. Styled-components

缺點:

  • 必須使用Styled-components預定義的語法糖,如styled.div("...")
  • 語法糖對css的封裝居然使用的是string,而使用string也就意味著我們將會失去一切可能的物件化操作css的機會。這與差不多10年前 AngularJS 1.x 時代對 html 的處理方法如出一轍,不得不說這種方式似乎是在開歷史的倒車。

不過,Styled-components 應該是CSS-in-JS最熱門的一個庫了,到目前為止github的star數已經超過了30k了。透過styled-components,你可以使用ES6的標籤模板字串語法(Tagged Templates)為需要styled的Component定義一系列CSS屬性,當該元件的JS程式碼被解析執行的時候,styled-components會動態生成一個CSS選擇器,並把對應的CSS樣式透過style標籤的形式插入到head標籤裡面。動態生成的CSS選擇器會有一小段雜湊值來保證全域性唯一性來避免樣式發生衝突。[2]

它既具備了 css-in-js 的模組化與引數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本[3]。

Styled-components官網

2. CSS module

import style from './index.css'
<div className={style.app}>

需要額外配置,ts環境需要配置*.d.ts的型別宣告檔案

declare module "*.css" {
    const css: {
        [key: string]: string //約定:匯出key所在的物件,原始的類名和內容都會和轉化為這個物件
    };
    export default css;
}

JSS 的好處

p.s. 接下來內容均轉自 知乎/進擊的大蔥/CSS in JS的好與壞

1. 區域性樣式 - Scoping Styles

CSS有一個被大家詬病的問題就是沒有本地作用域,所有宣告的樣式都是全域性的(global styles)。而CSS-in-JS會提供自動區域性CSS作用域的功能,你為元件定義的樣式會被限制在這個元件,而不會對其他元件的樣式產生影響。[2]

2. 避免無用的CSS樣式堆積

進行過大型Web專案開發的同學應該都有經歷過這個情景:在開發新的功能或者進行程式碼重構的時候,由於HTML程式碼和CSS樣式之間沒有顯式的一一對應關係,我們很難辨認出專案中哪些CSS樣式程式碼是有用的哪些是無用的,這就導致了我們不敢輕易刪除程式碼中可能是無用的樣式。這樣隨著時間的推移,專案中的CSS樣式只會增加而不會減少(append-only stylesheets)。

而因為CSS-in-JS會把樣式和元件繫結在一起,當這個元件要被刪除掉的時候,直接把這些程式碼刪除掉就好了,不用擔心刪掉的樣式程式碼會對專案的其他元件樣式產生影響。而且由於CSS是寫在JavaScript裡面的,我們還可以利用JS顯式的變數定義,模組引用等語言特性來追蹤樣式的使用情況,這大大方便了我們對樣式程式碼的更改或者重構。[2]

3 Critical CSS

放在head標籤內的CSS當然是越少越好,因為太多的內容會加大html的體積,所以我們一般把使用者需要在首屏看到的(above the fold)頁面要用到的最少CSS提取為Critical CSS。

CSS-in-JS透過增加一點載入的JS體積就可以避免另外發一次請求來獲取其它的CSS檔案。而且一些CSS-in-JS的實現(例如styled-components)對Critical CSS是自動支援的。[2]

4. 基於狀態的樣式定義

CSS-in-JS可以根據元件的狀態動態地生成樣式。[2]

5. 封裝得更好的元件庫

如果CSS是寫在JS裡面的,專案想要使用封裝的元件庫只需要進行簡單的npm install就可以了,非常方便。[2]

JSS 的壞處

p.s. 接下來內容均轉自 知乎/進擊的大蔥/CSS in JS的好與壞

1. 陡峭的學習曲線

首先CSS-in-JS是針對component-based的框架的,這就意味著要學習CSS-in-JS你必須得學習:component-based框架(例如React),JavaScript和CSS這三樣技能。其次,即使你已經會用React,JavaScript和CSS來構建SPA應用,你還要學習某個CSS-in-JS實現(例如styled-components),以及學習一種全新的基於元件定義樣式的思考問題方式。[2]

2. 執行時消耗

由於大多數的CSS-in-JS的庫都是在動態生成CSS的, 這就意味著會有一定的效能代價[2]

3. 程式碼可讀性差

大多數CSS-in-JS實現會透過生成唯一的CSS選擇器來達到CSS區域性作用域的效果。這些自動生成的選擇器會大大降低程式碼的可讀性,給開發人員debug造成一定的影響。[2]

4. 沒有統一的業界標準

CSS-in-JS只是一種技術思路而沒有一個社群統一遵循的標準和規範,所以不同實現的語法和功能可能有很大的差異。[2]

總結

CSS-in-JS有好處也有壞處,要不要使用完全取決於同學們自己的專案需求。例如在下面幾種情況下你就不需要它:

  1. 前端開發的初學者: 由於CSS-in-JS的學習坡度很陡,剛開始學習Web開發的同學沒必要學習,可能會有挫敗感。
  2. 功能簡單的靜態頁面:邏輯互動不復雜的網站沒有必要使用CSS-in-JS。
  3. 注重樣式可讀性以及除錯體驗: CSS-in-JS動態生成的選擇器很影響程式碼的可讀性,可能會降低你的除錯效率。

在我們的課程中,我們CSS-in-JS和普通的css我們都會使用,所以請同學們放心,進過本課程的學習,同學們基本上能掌握如何使用不同的方式來定義React的樣式了。

參考文獻

相關文章