小而美的 css 的原子化
小而美的 css 的原子化
http://zoo.zhengcaiyun.cn/blog/article/css
什麼是 CSS 原子化
引用 文章 Let’s Define Exactly What Atomic CSS is 中定義:
“
Atomic CSS is the approach to CSS architecture that favors small, single-purpose classes with names based on visual function.
譯文:
“
原子化 CSS 是一種 CSS 的架構方式,它傾向於小巧且用途單一的 class,並且會以視覺效果進行命名。
.bg-blue { background-color: #357edd; }
.f1 { font-size: 3rem; }
.m0 { margin: 0; }
通常情況下我們是怎麼寫 CSS 的
原子化 CSS 是一個 CSS 框架, 在沒有對應的 CSS 框架的項目中,是如何寫 CSS 的。我們引用 Challenging CSS Best Practices 文中例子來看看。
如圖所示:我們要實現一個類似訪問記錄組件,右邊是訪問人的頭像,左側是訪問的描述。
對應代碼.
<div class="media">
<a href="https://www.zcygov.cn/" class="img">
<img width="40" src="logo.png" alt="zcy" />
</a>
<div class="bd">@小明 14 分鐘之前</div>
</div>
<style>
.media {
margin: 10px;
}
.media,
.bd {
overflow: hidden;
_overflow: visible;
zoom: 1;
}
.media .img {
float: left;
margin-right: 10px;
}
.media .img img {
display: block;
}
</style>
新增一個設計,需要把頭像放在右側,描述在左側,如圖所示
我們通過新增一個類名 imgExt,右浮動
代碼:
<div class="media">
<a href="https://www.zcygov.cn/" class="imgExt">
<img width="40" src="https://sitecdn.zcycdn.com/f2e-assets/b37c37db-ce59-4bfe-a889-5c8615d008c8.png" alt="zcy" />
</a>
<div class="bd">@小明 14 分鐘之前</div>
</div>
<style>
...
/* 圖片在右側 */
.media .imgExt {
float: right;
margin-left: 10px;
}
</style>
這時候有來一個新設計,要求組件在頁面右側欄中時候,字體變小
代碼:
<div id="rightRail">
<div class="media">
<a href="https://www.zcygov.cn/" class="imgExt">
<img width="40" src="https://sitecdn.zcycdn.com/f2e-assets/b37c37db-ce59-4bfe-a889-5c8615d008c8.png" alt="zcy" />
</a>
<div class="bd">@小明 14 分鐘之前</div>
</div>
<style>
</div>
<style>
...
/* 頁面右側容器中時,字體變小 */
#rightRail .bd {
font-size: smaller;
}
</style>
用這種方式寫 CSS 存在存在以下的問題
-
一個簡單的樣式修改,都需要有新增一條樣式規則。面向業務 CSS 類的抽象,這就意味只能按照業務組件複用,比如例子中是一個訪問記錄,只能整個引用。其中單個規則是基本上是無法被再次複用的。人們通過習慣是按照新業務在聲明 CSS 類,複製已有相關已有功能,而不之一引用,因爲這裏類名和是業務綁定。
-
在例子中的 6 個樣式規則中,4 個是基於上下文的
-
新的需求與原有規則衝突,需要修改一個其中一個樣式,是通過新增一個嵌套類覆蓋原有的樣式
雖然文中的代碼樣例是 2013 年的,9 年過去了,發現自身的老項目中還是存在着類似問題。
- 按照業務聲明類名: 比如字符過長省略的樣式。多出重複。但是按照業務來命名 CSS 類又避免不了這個問題。
.text-overflow-dot {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
...
.title-number {
width: 55%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
...
.invoice-content {
div {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
- 類命名困難:缺失命名規範,不同人不同的風格,沒有什麼可讀性,給類取名字一個十分痛苦的事情,大多數時候類名不倫不類,難以讀懂。
.time-tip {
i {
margin-left: 10px;
cursor: pointer;
}
}
#service-charge-Bill {
.zcy-search-panel .ant-form-item-label {
min-width: 80px;
}
}
.invoice-tpl-container {
max-height: 360px;
overflow-y: scroll;
}
.add-invoice-tpl-item {
border: 1px dashed rgb(209, 215, 232);
text-align: center;
height: 160px;
line-height: 160px;
margin: 10px;
}
.invoice-tpl-item {
border: 1px solid rgb(209, 215, 232);
margin: 10px;
height: 160px;
position: relative;
.invoice-content {
overflow: hidden;
padding: 20px;
height: 119px;
div {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.invoice-type-mark {
display: inline-block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
color: white;
background-color: #3177fd;
}
}
.operate {
position: absolute;
bottom: 0;
width: 100%;
border-top: 1px solid rgb(209, 215, 232);
height: 40px;
line-height: 40px;
text-align: center;
}
}
.invoice-tpl-item.active {
border-color: #3177fd;
}
.default-mark {
position: absolute;
right: 0;
top: 0;
background-color: #bbb;
color: white;
padding: 0 5px;
}
-
大量的重複的 CSS 文件。現有項目大家都習慣將 CSS 文件創建在業務的目錄中,我的項目是用 webpack 構建的,開發階段 CSS 文件是按需加載的。這樣就存在一個問題,如果一個頁面也需要用另外頁面的樣式,開發同學第一反應是複製粘貼。很少發現同學用 @import 的方式,導致大量重複的 CSS 文件。
-
大量嵌套且使用 & 符號,無法搜索定位樣式,且可讀性極差
.catalogue {
&-title {
display: flex;
&-btns {
flex-grow: 1;
align-items: center;
text-align: right;
.ant-btn {
margin: 0 5px;
}
}
}
&-content {
height: calc(100% - 60px);
overflow: auto;
padding: 18px;
.cy-tree {
width: 80%;
}
.ant-tree {
overflow: auto;
}
}
&-tree {
height: calc(100% - 22px);
.ant-input {
width: 100%;
&-search {
width: 80%;
flex-grow: 1;
}
}
}
}
我們大多數項目是後臺管理的項目,自身也有一個成熟的組件庫。這樣的項目 CSS 的工作量是比較少的。所以項目開始之處,沒有指定對應 CSS 規範和架構,上訴的問題日積月累,導致現有項目 CSS 代碼狀況較差,維護起來讓人十分頭大,急需整理項目 CSS 框架和規範整體項目的 CSS。我們這邊調研幾個比較流行的 CSS 框架,以下是幾個框架簡要介紹。
CSS 框架介紹
原子化 CSS
定義
“
原子化 CSS 是一種 CSS 的架構方式,它傾向於小巧且用途單一的 class。
原則
“
class 的命名按照功能
class 的功能單一
相關資料
“
https://css-tricks.com/lets-define-exactly-atomic-css/
OOCSS (Object-Oriented CSS 面向對象 CSS)
定義
“
OOCSS (Object-Oriented CSS 面向對象 CSS) 是組織 CSS 的領先的模塊化或基於組件的系統。它是 Nicole Sullivan 在 2008 年在 Web Directions North 大會上首次提出的,核心就是編寫可複用和可維護的樣式。
原則
“
分離結構(structure)和皮膚(skin)。 您應該在基礎對象中保留結構和位置,並在擴展類中保留視覺特徵(如
background
或border
)。這樣您就不必覆蓋視覺屬性。分離容器(container)和內容(content)。 永遠不要在 CSS 中模仿 HTML 的結構。換句話說,不要在樣式表中引用標籤或 ID。相反,嘗試創建和應用描述相關標籤使用的類。並將嵌套類保持在最低限度。
相關資料
“
http://oocss.org/
SMACSS (Scalable and Modular Architecture for CSS)
定義
“
SMACSS(Scalable and Modular Architecture for CSS)編寫模塊化、結構化和可擴展的 CSS。
原則: SMACSS 認爲 CSS 有 5 個類別,我們通過這 5 種類別來拼湊出完整的 class
“
Base 基礎樣式
Layout 佈局樣式
Module 模塊樣式
State 狀態樣式
Theme 主題樣式
相關資料
“
http://smacss.com/
BEM( block, element, modifier)
定義
“
首先 BEM 是一個分層系統,它把我們的網站分爲三層,這三層正好對應着 BEM 三個英文單詞的簡寫 block, element, modifier,分爲爲 塊層、元素層、修飾符層
原則
“
使用
__
兩個下劃線將塊名稱與元素名稱分開使用
--
兩個破折號分隔元素名稱及其修飾符一切樣式都是一個類,不能嵌套
相關資料
“
https://getbem.com/
ITCSS
定義
“
理智、可擴展、可管理 CSS 架構
原則: 類似 SMACSS 對 CSS 元素進行了分層
“
Settings – 與預處理器一起使用,包含顏色、字體等定義
Tools – 工具與方法,比如 mixins,Settings 與 Tools 都不會產生任何 CSS 代碼,僅僅是輔助函數與變量
Generic – 通用層,比如 reset
html
、body
的樣式Elements – 對通用元素的樣式重置,比如
a
p
div
等元素的樣式重置 Objects – 類似 OOCSS 中的對象,描述一些常用的基礎狀態Components – 對組件樣式的定義,一個 UI 元素基本由 Objects 與 Components 組成
Utilities – 工具類,比如
.hidden
相關資料
“
https://getbem.com/
考慮到我們自身項目項目是一個後臺管理類的項目,有成熟組件庫。日常 CSS 開發工作量和複雜度不高。我們也希望有一個快速可以落地的框架方案,且實現的成本較低。我們對比幾個框架後,選擇 CSS 原子化作爲我們的 CSS 的架構方案。CSS 原子化提供現成的解決方案,幾乎就是拿就用( tailwindcss ,windicss )。而且成體接入和改造成本也是最低的,不用自己再製定命名規則和使用規範。
CSS 原子化是如何解決這些問題的
首先我們看看前文中提到組件使用 CSS 原子化是如何實現的,項目中已引入 winidicss。
<div class="overflow-hidden mr-1">
<a href="https://www.zcygov.cn/" class="float-left mr-1">
<img
width="30"
src="logo.png"
alt="zcy"
/>
</a>
<div class="overflow-hidden text-sm">@小明 14 分鐘之前</div>
</div>
這邊如果需要 頭像在右側的,只需要將 float-left 替換成 float-right 即可。
-
沒有了命名的煩惱,按照功能命名
-
沒有相關嵌套,整體可讀性加強
-
沒有重複 CSS 類, 一個功能對應一個類名,一個類名一個功能。沒有重複
-
沒有新增 CSS 文件了。所有類名都是有工具庫提供,項目中無需新增類了。
基本上解決了項目現有的 CSS 問題,而且 CSS 的維護性有了很大的提高,CSS 編碼的成本相對於以前有明顯的降低。
使用體驗
-
使用 vscode 的編輯器,建議安裝自動補全插件 (https://marketplace.visualstudio.com/items?itemName=voorjaar.windicss-intellisense),對於日常使用有很大的幫助,用起來的體驗也很好。
-
剛開始的時候對應功能的類名不熟悉,需要使用官網 (https://windicss.org/guide/) 查詢。
-
CSS 規範是要基於視覺的設計規範的,winidicss 工具提供了 design token 的設計規範實現,再推廣 CSS 的原子化之前和設計師統一好此類的規範,形成工具配置
import { defineConfig } from 'windicss/helpers'; import colors from 'windicss/colors'; export default defineConfig({ theme: { extend: { transitionProperty: { width: 'width', }, screens: { sm: '640px', md: '768px', lg: '1024px', xl: '1280px', }, colors: { gray: colors.coolGray, blue: colors.sky, red: colors.rose, pink: colors.fuchsia, }, fontSize: { xs: '.75rem', sm: '.875rem', tiny: '.875rem', base: '14px', lg: '1.125rem', xl: '1.25rem', '2xl': '1.5rem', '3xl': '1.875rem', '4xl': '2.25rem', '5xl': '3rem', '6xl': '4rem', '7xl': '5rem', }, }, }, });
使用過程中的問題
功能類優先的 原子化 CSS 框架,帶來便利的同時,也是存在一些問題的。最突出的問題就是 html 上類過多,如果要實現一個相同功能,需要複製一個很長的字符串。這個情況下的可讀性和複用性是比較差的。
比如一個簡單按鈕的例子:涉及到背景,字體,邊距,邊框的設置,類就很多
<button
class
>
Button
</button>
而且相同樣式複用需要整塊的複製。雖然這提供屬性化(https://windicss.org/features/attributify.html)的模式,Shortcuts(https://windicss.org/features/shortcuts.html)和指令(https://cn.windicss.org/features/directives.html)來解決相同功能類集合過長,過多的問題。但是實際上可以發現,原子化框架自身是無法解決這個問題的。
當然你有可以通過設計變量的方式來解決這個問題,但其實上和命名一個類名沒有多大的區別。
const myButtonClass = "bg-blue-400 text-sm text-white font-mono font-light py-2 px-4 border-2 border-rounded border-blue-200"
<button
className={myButtonClass}
>
Button
</button>
在選定一個 CSS 框架作爲項目的 CSS 規範的時候,需要考慮自身項目的現狀,如果項目本身 CSS 複雜度較高,整體工作量較多,原子化的 CSS 是不太適合的。
總結
原子化的 CSS 可以幫助我們的項目解決 CSS 命名,代碼重複,不斷膨脹的問題,但它也不是一勞永逸的,實際使用中還是會有問題,關鍵在與開發者自身的取捨,權衡利弊。不要一個規則用到底,遇到問題也不變通。工具和思想發明其實也是爲了解決你實際的問題。你會發現 windicss (https://cn.windicss.org/posts/v30-utilities.html) 這類工具優先的 css 框架,也是添加蠻多額外的功能來彌補原子化 CSS 框架的缺陷,提升自身使用體驗。
參考連接
-
Challenging CSS Best Practices (https://www.smashingmagazine.com/2013/10/challenging-css-best-practices-atomic-approach/)
-
Let’s Define Exactly What Atomic CSS is (https://css-tricks.com/lets-define-exactly-atomic-css/)
-
windicss (https://github.com/windicss/windicss)
-
tailwindcss (https://github.com/tailwindlabs/tailwindcss)
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/oMNhcQbN2ycOXkn-av1JVQ