- 原文:Atomic CSS-in-JS
- 時間:2020/04/27
- 做者:Sébastien Lorber
- 譯者:ziven27
- 翻譯時間:2020/05/10
譯者: 國內你們都去搞 JS 去了,能夠看到咱們有能夠與 REACT 抗衡的 VUE。卻顯見有相似 CSS-in-js, OOCSS,BEM,Atomic CSS ... 的 CSS 解決方案出現?這是爲何呢?css
隨着 Facebook 和 Twitter 最近的產品技術方案的迭代更新,咱們看到了一個新的流行趨勢: Atomic CSS-in-JS。vue
在這篇文章中,咱們將看到什麼是原子CSS,它是如何與像 TailwindCSS 這樣的 functional / utility-first CSS 之類技術方案的關係,以及哪些基於 react 框架的大廠是如何使用它的。react
由於我不是這方面的專家,因此不要期望深刻了解它的優缺點。我只是但願你能從對它的瞭解中有所啓發。git
注意: Atomic CSS 與 Atomic Design 設計無關。github
譯者注:Atomic CSS 是 CSS 代碼的一種設計模式,Atomic Design 是對於設計資源和設計組織方式的一種設計理念。web
你們可能據說過各類 CSS 解決方案,例如BEM,OOCSS ...npm
<button class="button button--state-danger">
Danger button
</button>
複製代碼
現在,人們愈來愈喜歡像 Tailwind CSS 同樣的 utility-first 概念。 這與 Functional CSS 和 Tachyon 很接近。react-native
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Button
</button>
複製代碼
使用一組實用程序類的樣式表,咱們其實能夠作得更多。設計模式
Atomic CSS 能夠看做是 utility-first CSS 的一種極致抽象: 全部的 CSS 類都有且只有一個單一的,獨特的 CSS 規則。Thierry Koblentz (Yahoo!) 在 2013年 的「 Challenging CSS Best Practices」 首次提到了 CSS。緩存
/* Atomic CSS */
.bw-2x {
border-width: 2px;
}
.bss {
border-style: solid;
}
.sans {
font-style: sans-serif;
}
.p-1x {
padding: 10px;
}
/* Not atomic, because the class contains 2 rules */
.p-1x-sans {
padding: 10px;
font-style: sans-serif;
}
複製代碼
咱們不得不認可在使用 utility/atomic CSS 時,是將結構層和樣式層耦合在了一塊兒:當咱們須要更改按鈕顏色時,咱們修改的是 HTML,而不是 CSS。 這種緊密耦合的方式在現代 CSS-in-JS React 代碼庫中也獲得了承認,但這個現存的「關注點分離」的主流思是相違背的。
由於咱們使用簡單的類選擇器,因此「關注點分離」也再也不是什麼大的問題。
咱們如今經過結構來修改樣式,會有如下幾個特色:
固然這會增大 HTML 的體積。對於服務器渲染的 Web 應用程序,可能會是一個問題,可是利用 gzip 能夠很好地壓縮類名中的高冗餘度,這和壓縮 CSS 文件中重複 CSS 樣式的方式同樣。
你不須要在任何狀況下都使用 utility/atomic CSS , 它更適合大多數通用的樣式素材。
譯者注:也就是 Design Token,Atomic CSS 在對接 Design Token 會發揮出它最大的優點
一旦定義好 utility/atomic CSS,它就很難改變或增加。 利用這個特性,咱們就能夠主動將它緩存(例如,把它添加到 vendor.css 中,並不須要每次都從新部署)。 它移植行也很是高,能夠很方便的在其餘應用程序中使用。
Utility/atomic CSS 很是的棒, 可是它也有一些坑。
一般咱們會在項目初期手動建立 utility/atomic CSS,並制定好命規則。 但這很難確保它的易用性,以及控制它的膨脹率。 這個可以在讓多我的使用的狀況下保持一致嗎? 是否受bus factor因素影響?
譯者注: bus factor 我猜想是指的代碼裏面的破窗效應。
Tailwind 的方法很是方便,能夠解決其中的一些問題。
它並無真正爲全部網站提供惟一的 utility CSS 文件。相反,它僅提供共享的做用域和命名約定。經過配置文件,您能夠生成屬於本身的utility CSS。
Tailwind的知識能夠移植到其餘應用程序,即便它們沒有使用徹底相同的類名。這讓我想起了React的「學習一次,隨處寫」的哲學。
我見過有人提到說,Tailwind 的類,幾乎能知足了他們平常 90% 或 95% 的樣式需求。這個覆蓋面已經足夠大了,咱們一般不須要使用一次性樣式。
基於這個點您可能會想知道爲何要用 Atomic CSS 來替代 Tailwind 呢?
在嚴格遵照 Atomic CSS 中一個 Class 只有一條規則的邏輯下你會獲得什麼?您最終將得到更大的 HTML 標記,和不方便的命名約定?無論怎麼樣,Tailwind 已經內置了許多原子類。
所以,咱們應該放棄 Atomic CSS 的想法,而選擇看起來更簡單的 Tailwind ?
Tailwind 是一個很是棒的解決方案,可是仍然存在一些還沒有解決的問題:
與 Tailwind 相比,手寫 Atomic CSS 樣式並非一個好的方案。
CSS-in-JS, and utility/atomic CSS 仍是有不少共同點的。兩種方法都主張從標記中進行樣式化,相似寫內聯樣式,這使它們具備許多類似的屬性(例如,能夠放心地移動內容)。
Christopher Chedeau 極大地幫助了在 React 生態系統中傳播 CSS-in-JS 的想法。 在屢次talks中,他解釋了CSS的問題:
Utility/atomic CSS CSS-in-JS / atomic CSS 解決了其中的一些問題,但顯然不是所有(特別是樣式的不肯定性解析)。
若是它們具備如此多的類似性,咱們不能同時使用它們嗎?
Atomic CSS-in-JS 能夠看做是 「自動化的 atomic CSS」:
我不知道目前全部 CSS-in-JS 庫對於 Atomic css 的支持狀況。 支持它其實是 CSS-in-JS 庫的實現細節。支持狀況多是有的有,有的沒有,或者是可選項。
我將重點推薦如下兩個解決方案,這致使最近出現了兩個大規模的原子CSS-in-JS 的使用:
React-Native-Web 是一個很是有趣的庫:它容許在 Web 上渲染 React-Native。 這裏咱們並非真正在談論跨平臺的 移動/ Web開發(請從論壇以獲取更多詳細信息)。
做爲一名Web開發人員,你只須要了解 React-Native-Web 是一個常規的 CSS-in-JS 庫,帶有一小部分原始的 React 組件。 不管您在何處看到 View,均可以將它替換爲div,這是您的最佳選擇。
React-Native-Web 由 Nicolas Gallagher 建立,致力於 Twitter 移動端。 他們逐步將其部署到移動設備上,不肯定確切時間,但可能在 2017/2018 年左右。 從那時起,它已被其餘公司(大聯盟足球,Flipkart,Uber,泰晤士河…)使用,但最重要的部署是 Paul Armstrong 領導的團隊開發的新的 2019 Twitter 桌面應用程序。
Stylex 是在 Facebook 上開發的新 CSS-in-JS 庫,用於 2020 年 Facebook 重寫(當前爲beta)。 看來他們計劃有朝一日將其開源,可能使用不一樣的名稱。
值得一提的是,React-Native-Web 的做者 Nicolas Gallagher 是 2 年前被 Facebook 聘用的。 看到它的某些概念被 Facebook 重用也就不足爲奇了。
與 React-Native-Web 不一樣,Stylex 彷佛並不專一於跨平臺開發。
我收到的全部信息都來自論壇 :) 咱們將不得不等待更多詳細信息。
正如 Atomic CSS 所指望的那樣,Twitter 和 Facebook 的 CSS 都已經大幅減小了,他們都遵循圖中的曲線。 雖然仍是須要爲一些應用付出努力。
Facebook給到的具體數字:
這兩個庫彷佛有一個類似且至關簡單的API,可是很難說,由於咱們對 Stylex瞭解很少。
值得強調的是,React-Native-Web 會處理 CSS 縮寫 和 margin: 0;
這樣的語法。
讓咱們看看 Twitter 上的 HTML 是什麼樣的:
再看看新的 Facebook:
不少人看到這個可能會嚇一跳,但不得不認可它確實有效,並且仍然可使用。
在 Chrome 檢查器中瀏覽樣式可能有點困難,但 devtools 能夠幫助:
和手寫 utility/atomic CSS 不同的是,JS 庫可以使樣式不依賴於 CSS 規則的插入順序。咱們都知道,在規則衝突的狀況下,獲勝的不是 class 屬性的最後一個類,而是在樣式表中最後插入的規則。 咱們只能經過使用簡單的基於類的選擇器來解決特異性問題。
實際上,這些庫避免在同一元素上輸出具備衝突規則的類。 他們確保標記中聲明的最後一個樣式始終獲勝。 「覆蓋的類」已被過濾,甚至沒有進入 DOM。
const styles = pseudoLib.create({
red: {color: "red"},
blue: {color: "blue"},
});
// That div only will have a single atomic class (not 2!), for the blue color
<div style={[styles.red, styles.blue]}>
Always blue!
</div>
// That div only will have a single atomic class (not 2!), for the red color
<div style={[styles.blue, styles.red]}>
Always red!
</div>
複製代碼
若是一個類有多個規則,而其中只有一個被覆蓋,則 CSS-in-JS 庫將沒法過濾該類而不刪除非覆蓋的規則。
若是一個 class 有一條簡單的縮寫規則,例如 margin:0
,可是覆蓋它的樣式是 marginTop:10
,會遇到一樣的問題。 若是 margin:0
的簡寫語法被擴展爲 4 個不一樣的類(marginTop:0;marginLeft:0; marginRight:0; marginBottom:0
),這些庫就可以過濾出不該出如今 DOM 中被覆蓋的類。
一旦瞭解了全部 Tailwind 命名約定,就能夠很是快速地編寫 UI。就很難再回到相似 CSS-in-JS 那樣手工一行行去寫樣式的方式。
Nothing prevents you for building your own abstractions on top of an atomic CSS-in-JS framework. Styled-system might be able to run some of the CSS-in-JS libraries supporting atomic CSS. It’s even possible to reuse naming conventions for Tailwind in JS, if you feel you are productive with it.
沒有什麼能夠阻止你在Atomic CSS-in-JS 框架之上構建本身的抽象。 Styled-system可讓不少 CSS-in-JS 的庫支持 Atomic CSS。若是你仍是更喜歡 Tailwind 的方式,你甚至能夠改寫 Tailwind 在 JS 中的命名規則。
這是傳統 Tailwind 的寫法:
<div className="absolute inset-0 p-4 bg-blue-500" />
複製代碼
咱們隨便找一個方案(react-native-web-tailwindcss) 我在goole 上看到的。
import {t} from 'react-native-tailwindcss';
<View style={[t.absolute, t.inset0, t.p4, t.bgBlue500]} /> 複製代碼
就生產率而言,這並無太大不一樣。 並且您可使用 TypeScript 規避一些輸入錯誤的問題。
關於Atomic CSS-in-JS,我想說的就這些。
我從未在任何大型生產環境項目中使用過Atoatomic CSS, atomic CSS-in-JS 或着 Tailwind 。 我可能在某些地方錯了,請隨時在Twitter上糾正我。
我認爲原子CSS-in-JS在React生態系統中是一種趨勢,我但願您從這篇文章中學到了有用的東西。
因爲我尚未找到任何關於原子CSS-in-JS的文章,因此這篇文章主要是爲我本身寫的。當我在之後的博客文章中提到原子CSS-in-JS時,我但願有一個資源連接(我計劃撰寫更多關於React-Native-Web和跨平臺的文章,敬請關注)。
感謝您的閱讀。
Atomic CSS 我不知道已經推薦了多少次了,這麼說吧它是目前現存的方案中,能解決 CSS 難題最多的解決方案沒有之一。特別是在基於組件化思惟的react 或者 vue 項目中使用。
另外再推薦一個本身多年 Atomic CSS 使用下來的經驗總結的一個 npm 庫。
名稱 | NPM | github |
---|---|---|
@_nu/css-acss |
能夠把@_nu/css-acss
理解爲閹割版的 Tailwind。用閹割來換取上手成本和使用體驗。五分鐘看完文檔你就能理解全部的邏輯。
我的能力和翻譯水平有限,有錯誤歡迎指正