您當前的位置:首頁 > 體育

一文詳解 CSS-in-JS

作者:由 阿里開發者 發表于 體育時間:2021-02-10

簡介:

CSS-in-JS是一種樣式化技術,其中 JavaScript 用於樣式化元件。解析此 JavaScript 時,將生成 CSS(通常作為

image.png

image.png

幾年前,如果有人提到用 JavaScript 編寫 HTML 作為構建大型網站的一種方式,很多開發者會當這作不可理喻的想法,但是現在,使用 React、Vue 和 Angular 框架為元件開發的應用正在慢慢替代傳統的 Web 開發。

現在 CSS-in-JS 確實也有點像當年的味道,雖然並不是唯一的解決方案,卻提供了一個很大膽的想法和嘗試。

對現代化的 Web 開發專案說,CSS 也是如此,CSS 做為 Web 的樣式表來呈現豐富多彩的 Web 應用已經不再是唯一的選擇了,我們或許應該多考慮其他的擴充套件性和移植性嘗試未來的 CSS-in-JS。

一 CSS 的介紹

CSS(層疊樣式表)是一種用來為結構化文件新增樣式的計算機語言,由 W3C 定義和維護。目前最新版本是 CSS2。1,為 W3C 的推薦標準。CSS3 現在已被大部分現代瀏覽器支援,而下一版的 CSS4 仍在開發中。

1 模組和標準化程序

CSS Level 2 經歷了 9 年的時間(從 2002 年 8 月到 2011 年 6 月)才達到 Recommendation(推薦) 狀態,主要原因是被一些次要特性拖了後腿。為了加快那些已經確認沒有問題的特性的標準化速度,W3C 的 CSS Working Group(CSS 工作組) 作出了一項被稱為 Beijing doctrine 的決定,將 CSS 劃分為許多小元件,稱之為_模組_。這些模組彼此獨立,按照各自的進度來進行標準化。其中一些已經是 W3C Recommendation 狀態,也有一些仍是 early Working Drafts(早期工作草案)。當新的需求被肯定後, 新的模組也會同樣地新增進來。

第一個 CSS 於1996年推出,下面是 CSS 版本的時間表:

1996年 CSS 1。0釋出

1998年 CSS 2。0釋出

2011年 CSS 2。1釋出

今天,CSS3 模組擴充套件了 CSS 2。1

image.png

image.png

2 CSS 模組狀態

從形式上來說,CSS3 標準自身已經不存在了。每個模組都被獨立的標準化,現在標準 CSS 包括了修訂後的 CSS2。1 以及完整模組對它的擴充,模組的 level(級別)數並不一致。可以在每個時間點上為 CSS 標準定義一個 snapshots(快照),列出 CSS 2。1 和成熟的模組。

W3C 會定期的釋出這些 snapshots,如 2007, 2010, 2015 或 2017。

目前為止,還沒有 level 超過 3 的模組被標準化,未來應該會有所改變。不過有些模組,比如 Selectors(選擇器)4 或 CSS Borders and Backgrounds(邊框和背景)Level 4 早已擁有了 Editor‘s Draft(編輯草案),即使它們還沒達到 First Published Working Draft(初次釋出工作草案)狀態。

image.png

image.png

3 五種 CSS 設計模式

現代化的前端開發在歷史上發展了許多的 CSS 設計模式,主要發展出以下幾種:

OOCSS(Object Oriented CSS)

SMACSS(Scalable and Modular Architecture for CSS)

BEM(Block - Element - Modifier)

ITCSS(Inverted Triangle Cascading Style Sheets)

Atomic CSS

其設計的原因基本是基於這幾個問題來做最佳化的:

減少選擇器命名和樣式的衝突

清晰的 CSS 整體結構

去除冗餘程式碼,減少樣式的體積

可重複利用,元件化的 CSS

提高 CSS 程式碼的可讀性

4 Atomic CSS 的歷史

image.png

image.png

2013/06/10:Brad Frost 釋出了 Atomic Design 文章,在社群上有一些文章開始討論 Atomic CSS

2015/01/08:《atomic design: the book》 一書釋出

2014/10/02:atomizer 專案建立

2017/10/06:tailwindcss 專案建立

Tailwind CSS 和其他預編譯器相比還是比較的冷門,如下圖:

image.png

image.png

在 React 和 Vue 日益吞噬的 Web 開發界中,元件化的思想和工程化日漸成熟,Atomic CSS 也算是比較早推出的一個設計思想,筆者覺得 Atomic CSS 能做的事情,在 CSS-in-JS 反而能做的更好,因為 JS 框架和工具的盛行和豐富,Atomic(原子化)也是未來 CSS-in-JS 一個可以涉足的區域。

5 CSS 數學表示式

根據 CSSWG 的 draft,CSS 目前支援計算的數學表示式主要包含五大類:

基本算數:calc()

比較函式:min(), max(), clamp()

步進函式:round(), mod(), rem()

三角函式:sin(), cos(), tan(), asin(), acos(), atan(), atan2()

指數函式:pow(), sqrt(), hypot(), log(), exp()

日常使用中 calc() 算是最常用的,一般用來計算長寬、響應式佈局等等,而比較函式在一些場景也可能會用的上,剩下的其他函式很大部分都沒有機會在專案中使用的上。

image.png

image.png

6 CSS Houdini

Houdini是一組底層API,它們公開了CSS引擎的各個部分,從而使開發人員能夠透過加入瀏覽器渲染引擎的樣式和佈局過程來擴充套件CSS。Houdini是一組API,它們使開發人員可以直接訪問CSS 物件模型 (CSSOM),使開發人員可以編寫瀏覽器可以解析為CSS的程式碼,從而建立新的CSS功能,而無需等待它們在瀏覽器中本地實現。

—— 《MDN / CSS Houdini》

如果說 CSS-in-JS 是用現有的標準用 JS 去控制、擴充套件和實時聯動 CSS 的一套方案,那麼 CSS Houdini 就相當於進階版本的 CSS-in-JS,透過公開 CSS 引擎的各個功能,是開發人員能更好的擴充套件 CSS,筆者認為是不是也可以理解為 CSS Houdini 的出現也代表了現在的純 CSS 已經很難滿足現在日益豐富的 Web 應用。

image.png

image.png

CSS Houdini

CSS Parser API

這是直接地暴露出 CSS 解析器的 API介面,能夠把任意 CSS 類語言解析成為一種中間型別,定義新的結構。

CSS Properties and Values API

定義一個用來註冊新的 CSS 屬性的 API。透過該 API 註冊的屬性必須用一種特定的解析語法書寫,以定義其型別、繼承行為以及初始值。

CSS Properties and Values API reference

CSS Properties and Values API guide

CSS Typed OM

可以把 CSS Typed OM 視為 CSSOM 2。0,它的目的在於解決目前模型的一些問題,並實現 CSS Parsing API 和 CSS 屬性與值 API 相關的特性。

CSS Typed OM reference

CSS Typed OM guide

CSS Layout API

被設計來提升 CSS 擴充套件性的 API,該 API 能夠讓開發者去書寫他們自己的佈局演算法,比如 masonry 或者 line snapping。

CSS Painting API

被設計來提升 CSS 擴充套件性的 API,該 API 允許開發者透過 paint() 方法來寫 JavaScript 函式,以控制繪製頁面元素的樣式或內容區域。

CSS Painting API reference

CSS Painting API guide

Worklets

該 API 允許指令碼獨立於 JavaScript 執行環境,執行在渲染流程的各個階段。

Worklets 在很接近於 JS 的 Web Workers ,由渲染引擎擴充套件並呼叫。

Worklets reference

7 CSS 預處理器 (CSS Preprocessor)

CSS 預處理器是一個能讓你透過預處理器自己獨有的語法來生成 CSS 的程式。市面上有很多 CSS 預處理器可供選擇,且絕大多數 CSS 預處理器會增加一些原生 CSS 不具備的特性,例如程式碼混合,巢狀選擇器,繼承選擇器等。這些特性讓 CSS 的結構更加具有可讀性且易於維護。

—— 《MDN / CSS 預處理器》

一些最流行的 CSS 預處理器:

PostCSS:2013/11/04

Less:2009

SASS:2006/11/28

Stylus:2010/12/29

image.png

image.png

圖中看到 PostCSS 的下載量一直遙遙領先其他 CSS 預處理器,PostCSS 比較大的優勢在於社群有很多外掛可以使用,相當於 CSS 屆的 Babel,常見 PostCSS 外掛如下:

Autoprefixer:自動補全瀏覽器私有字首

precss:CSS 預處理(整合 Sass、LESS 或 Stylus 功能,語法基本和 Sass 的相同)

postcss-import:透過 @import,整合多個 CSS 檔案

css-mqpacker:將相同的 CSS 媒體查詢規則合併為一個

cssnano:壓縮 CSS 檔案

postcss-color-rgba-fallback:給 rgba 顏色建立降級方案(新增備用顏色)

postcss-opacity:給 opacity 提供降級方案(給 IE 瀏覽器新增濾鏡屬性)

node-pixrem:讓 IE8 ⽀持 rem 單位

postcss-pseudoelements:將偽元素的 :: 轉換為 : ( IE8 不不⽀支援 ::)

image.png

image.png

如果一定需要使用 CSS 預處理器,可能 PostCSS 是最好的選擇之一,當然,也是需要看實際你專案的整體方案來選擇。

8 CSS-in-JS VS CSS Preprocessor

image.png

image.png

在 Google Trends 中我們可以看到 2014 年後 CSS-in-JS 的趨勢就逐漸超越了 CSS 預處理器,這在一方面也說明了開發人員在 CSS-in-JS 上有著很大興趣。

二 CSS-in-JS 的介紹

CSS-in-JS是一種樣式化技術,其中 JavaScript 用於樣式化元件。解析此 JavaScript 時,將生成 CSS(通常作為

1 CSS-in-JS 起源歷史

2000年11月13日:W3C 草案中 Document Object Model (DOM) Level 2 Specification 提出了 CSS Object Model (CSSOM),允許 CSS 透過 JavaScript 操縱的。它非常類似於 DOM,但是用於 CSS 而不是 HTML。它允許使用者動態讀取和修改 CSS 樣式。

2014年11月15日:CSS-in-JS 由 Facebook 的員工 Vjeux 在 NationJS 會議上提出:可以借用 JS 解決許多 CSS 本身的一些“缺陷”,比如全域性作用域、死程式碼移除、生效順序依賴於樣式載入順序、常量共享等等問題。

2014 ~ 現在:大量的 CSS-in-JS 的解決方案的提出,在領域上不斷除舊推新,在工程化和框架的解決方案中不斷探索實現。

CSS-in-JS 的一大特點是它的方案眾多,這種看似混亂的狀態很符合前端社群喜歡重複造輪子的特徵。發展初期,社群在各個方向上探索著用 JS 開發和維護 CSS 的可能性。每隔一段時間,都會有新的語法方案或實現,嘗試補充、增強或是修復已有實現。

2 沒有 CSS 的那些平臺和框架

QT:QStyle Class & Draw Method

Flutter:Style Object

ReactNative:ReactNative。StyleSheet

Unreal Engine:Style Object

Canvas:Draw Method

Skia:Draw Method

都是基於各自的設計 imperative & declarative(命令式和宣告式)的樣式編寫,能與程式設計中的各個狀態繫結,並不侷限於樣式表修改這一概念。

3 區別是什麼

如果說純 CSS 框架工具和 CSS-in-JS 的區別是什麼,筆者覺得最大的區別就是編譯執行的不同時機,我們可以理解成:CSS 框架工具只等於 AOT(Ahead-of-time),CSS-in-JS 則擁有 JIT(Just-in-time) 的能力,例如上面提到的 CSS Houdini API 本質其實也是相當於擴充套件 CSS 框架的實時執行的能力,而 JIT 的框架和工具本質上也可以使用 AOT 的工具來最佳化,例如 Babel 和 Webpack。

4 使用 CSS-in-JS 的優點

元件化思考模式,不再需要維護一堆樣式表。CSS-in-JS 將 CSS 模型抽象到元件級別,而不是文件級別(模組化)。

CSS-in-JS 利用 JavaScript 環境的全部功能來增強CSS。

真正的選擇器隔離。範圍選擇器是不夠的。CSS具有從父元素自動繼承的屬性(如果未明確定義)。

CSS 要避免選擇器衝突,例如 BEM 之類的命名約定可能在一個專案中有所幫助,但在整合第三方程式碼時則會存在很多問題。當 JSS 將 JSON 表示形式編譯為 CSS 時,預設情況下會生成唯一的類名。

動態瀏覽器私有化字首,使用 CSS-in-JS 可以避免臃腫的 CSS 程式碼。

程式碼共享,輕鬆在 JS 和 CSS 之間共享常量和函式。

CSS-in-JS 的單元化測試。

TypeScript 的支援。

減少專案編譯的依賴,純 JS 或 TS 專案。

動態變化的主題和變數。

5 使用 CSS-in-JS 的缺點

學習曲線,需要學習使用

新的依賴

6 那些流行的 CSS-in-JS 庫

Run-Time(JIT)

執行時動態修改樣式的庫:

emotion

jss

styled-components

aphrodite

radium

glamor

如下圖統計,emotion、jss 和 styled-components 都有不錯的開發者 NPM 下載使用量,保持長期的增長趨勢,這對開發者來說是比較不錯的,意味著這些庫也有穩定的發展和維護。

image.png

image.png

逐年遞增的下載數量反映了開發社群和使用範圍的擴大,也表明了開發者在 CSS-in-JS 上的積極貢獻和參與。

image.png

image.png

這些庫大部分的動態修改樣式主要使用這幾種方式:

1)CSS 樣式表

Scoped CSS:透過每個元件新增 CSS 樣式表,但是添加了 scoped 的作用域

Global CSS:在 HTML 全域性新增修改樣式表的 Content 來修改樣式

2)CSSOM 修改

透過修改全域性的 CSSOM 的 CSSRule 來達到修改樣式的目的

這幾種方式,筆者比較推薦 CSSOM 修改的方式,頁面的 HTML 結構和內容不會變化,也不會有過多的單元件 CSS,而且在修改樣式方式上也有很多可以最佳化和擴充套件的餘地,期望後續的開發者能有優秀的實踐可推廣。

Build-Time(AOT)

提前編譯成 CSS 樣式表的庫:

Linaria

提前編譯的優勢在於一些小程式和其他框架需要 CSS 樣式表時是唯一的選擇,在使用者低端手機和效能上比動態修改樣式要更有優勢。

7 都有誰在使用?

UI 庫

material-ui 是筆者很早關注的一個 material design 的一個開源 UI 元件庫,用過 ReactJS 的開發同學可能有了解過,記得一開始官方採用的是內聯樣式,後續研發了自己的一套 CSS-in-JS 的實現方案,單獨釋出了 Material-UI 元件中使用的樣式方案 —— @material-ui/styles。

公司

數千家公司正在使用 CSS-in-JS 進行開發 Web 應用。

Google

Facebook

Reddit

Patreon

Target

Atlassian

Vogue

GitHub

Coinbase

8 Chrome Devtools 對 CSS-in-JS 的支援

在 What’s New In DevTools (Chrome 85) 中 Google 更新了 CSS-in-JS 框架的樣式編輯的支援。

現在,“Styles”窗格對編輯使用 CSS 物件模型(CSSOM)API 建立的樣式提供了更好的支援。許多 CSS-in-JS 框架和庫都在底層使用 CSSOM API 來構造樣式。

現在也可以使用 “Constructable Stylesheets” 編輯在 JavaScript 中動態新增的樣式。

可構造樣式表是使用 Shadow DOM 時建立和修改樣式的一種新的方法。

例如,(CSSOM API)h1新增的樣式 CSSStyleSheet以前不可編輯。現在可以在“Styles”窗格中進行編輯:

image.png

image.png

三 UI & Code 3。0 新時代

1 自動智慧化

在現在前端開發趨勢越來越智慧化的時代,如果用上 CSS-in-JS 在未來的無論是輸出還是輸入都有很大的便利性和可控性。

假如把前端和設計的協同工作分為三個時代:

v1。0:設計資源和資訊需要設計師手動額外切圖說明,無法複製

v2。0:設計資源和資訊由設計檔案自動化生成,可人工複製

v3。0:設計資源和資訊由設計原始檔和程式碼自動讀取,無需人工複製

image.png

image.png

也就是說,可以透過介面、SDK或外掛,可以把設計檔案的資源和資訊讀取到程式碼中,減少人工維護和開發的成本,建立起是設計和程式的橋,方便雙方的協同工作。

image.png

image.png

現如今,很多設計軟體都推出了自己的一套外掛或 SDK 以供開發者使用,如下圖 Sketch 外掛的開發:

image.png

image.png

2 跨平臺

CSS-in-JS 在跨平臺的優勢是比較大的,在不同的系統平臺上都有 JS 的 Runtime 的實現,而且 JSON 序列化後的資料也能被更多的平臺和語言消費,現在光靠純 CSS 是無法達到這種通用性和擴充套件性。

image.png

image.png

四 展望未來

CSS 設計的初衷是為了全域性化的控制樣式,透過選擇器去擴充套件豐富實際的頁面渲染,而 CSS-in-JS 並不是排斥 CSS 樣式,而是說“樣式”在現代化的元件顆粒化的發展下,使用 CSS-in-JS 能在瞬息萬變的複雜應用場景下更加靈活的解決更多問題。

筆者因早前開發過自己的一套 React UI 庫 React-UWP,也基於這套 UI 庫做了 CSS-in-JS 的方案,在過去兩年中在開發中雖然用的元件不是很多,但是用了 CSS-in-JS 來做整體的樣式解決方案,在元件擴充套件、主題自定義和狀態同步有著很大的優勢,也期望在後續的社群中有更多優秀的實踐可以參考。

如果在文章中發現有誤之處,歡迎反饋、糾正。

Links

https://www。

w3。org/Style/CSS20/hist

ory。html

https://

levelup。gitconnected。com

/a-brief-history-of-css-in-js-how-we-got-here-and-where-were-going-ea6261c19f04

https://

github。com/MicheleBerto

li/css-in-js

https://

zhuanlan。zhihu。com/p/16

5089496

https://

zhuanlan。zhihu。com/p/10

3522819

https://

zhuanlan。zhihu。com/p/59

692295

https://

zhuanlan。zhihu。com/p/30

118092

https://

medium。com/dev-channel/

the-cost-of-javascript-84009f51e99e

https://

juejin。cn/post/68449038

08049348616

https://www。

infoq。com/news/2020/04/

facebook-cssinjs-react-conf-2019/

https://

sebastienlorber。com/ato

mic-css-in-js

https://www。

nonenglishengineer。com/

css-design-patterns/

https://

dev。to/carlillo/underst

anding-itcss-real-case-using-itcss-in-a-ghostcms-blog-1p9b

https://

engineering。fb。com/2020

/05/08/web/facebook-redesign/

https://

zhuanlan。zhihu。com/p/98

831543

https://www。

qed42。com/blog/building

-powerful-custom-properties-CSS-houdini

https://

laptrinhx。com/the-futur

e-of-css-has-come-3034181035/

https://

zhuanlan。zhihu。com/p/20

939640

https://www。

smashingmagazine。com/20

16/03/houdini-maybe-the-most-exciting-development-in-css-youve-never-heard-of/

https://

developer。mozilla。org/z

h-CN/docs/Archive/CSS3

http://www。

airbrite。co。uk/css-trai

ning-css-specification/

https://

aotu。io/notes/2019/10/2

9/css-preprocessor/index。html

https://

zhuanlan。zhihu。com/p/36

103933

https://www。

w3。org/Style/CSS/curren

t-work。en。html

https://

github。com/ladjzero/lad

jzero。github。io/blob/master/assets/a_brief_history_of_css。pdf

https://

developer。mozilla。org/e

n-US/docs/Web/Houdini

https://

drafts。csswg。org/css-va

riables-1/

https://

drafts。csswg。org/css-va

lues-4/

https://

juejin。cn/post/68449041

52548507661

https://

engineering。fb。com/2020

/05/08/web/facebook-redesign/

https://

css-tricks。com/growing-

popularity-atomic-css/

https://

css-tricks。com/lets-def

ine-exactly-atomic-css/

https://www。

smashingmagazine。com/20

13/08/other-interface-atomic-design-sass/

https://www。

smashingmagazine。com/20

13/10/challenging-css-best-practices-atomic-approach/

https://

bradfrost。com/blog/post

/atomic-web-design/

https://

bradfrost。com/blog/post

/atomic-design-book/

版權宣告:

本文內容由阿里雲實名註冊使用者自發貢獻,版權歸原作者所有,阿里雲開發者社群不擁有其著作權,亦不承擔相應法律責任。具體規則請檢視《阿里雲開發者社群使用者服務協議》和《阿里雲開發者社群智慧財產權保護指引》。如果您發現本社群中有涉嫌抄襲的內容,填寫侵權投訴表單進行舉報,一經查實,本社群將立刻刪除涉嫌侵權內容。

標簽: CSS  js  com  API  樣式