前言
我們的第一步是先從 CSS 下手,因為 css 是相對於其他前端部分來說比較容易重構的部分。很容易髒亂的 code 也是 CSS。
上一篇描述了在大型專案中引入新框架及技術的困難點,這一篇主要會專注在如何透過現有的工具及框架來重構現有的代碼。
本次的重構技巧會以 SCSS 為主,所以在閱讀本文之前,我先假設你已經有基本的 SCSS 以及 CSS 的基礎。其他預處理器的概念應該是相通的。
引入 style linter 及 editorconfig
我們採取的第一步是先引入審查代碼工具。目前比較流行的 css linter 是 stylelinter,他能夠針對 scss sass 語法做 lint。也可以搭配其他 IDE、文字編輯器 plugin。這邊的範例是使用 sublime,其他的 IDE 應該也有類似的功能。
1. 加入 stylelint
stylelint 除了可以針對 scss 語法做 lint 之外。由於其本身是用 js 撰寫的,可以客製化自己的 rule 跟加入其他開源的 plugin。
因為 stylelint 是以 AST 的方式解析,所以可以很容易的對文件中的節點做操作。
關於 stylelint 的深入使用,已經超過本文篇幅,有興趣的人可以參考 css trick 的教學
首先,先來安裝 stylelint
,run npm install -g stylelint
。
再來設置 .stylelintrc 檔,詳細的 rules 可以到這裡 查看。如果你不想要那麼麻煩自己手動一個一個設定的話。可以考慮使用 stylelint-config-standard 這個插件,再根據自己的需求做調整。
npm install --save-dev stylelint-config-standard
這邊還是建議花時間瞭解一下專案的需求來制定 rule,不然有時候太嚴格的 rule,滿江紅看到也懶得改了。
2. 加入 .editorconfig
EditorConfig 是一個為了統一代碼風格的解決方案。每個人文字編輯器的環境可能不盡相同,為了統一彼此之間的環境,這邊我們採用的 editorconfig
設定非常簡單,只要新增一個檔案就好。editorconfig。
目前幾乎主流的文字編輯器都有支援 editorconfig。
常見的 code smell 以及 refactor 方式
在開始捲起袖子做事之前,還是先來確認一下目前的專案是否需要 refactor:
- 許多元件(如 button input)等放在同一個檔案內,查找非常不易。
- 覆寫了許多 class 造成預期之外的行為發生
- 早期沒有統一的代碼規範,tab、空白夾雜在一起,閱讀性大幅降低
- !important 四散各處
- 變數的命名跟管理不夠統一
- 團隊開始擴增
- 相關的文件不足
接下來介紹一些比較常見的 code smell
Order
class 變多之後,如果 rule 裡面沒有一定的排列順序的話,其實查找很不方便。而且易讀性並不高,像是下列的 code
|
|
那麼要怎樣排序會比較好呢?這邊提供幾個大原則:
- display、position
- box-model
- font、typography
- layout(包含 color、border-radius 等)
- 其他屬性(如animation)
原因:對一個 class 來說,最重要的就是 display 與 position ,所以應該擺在最上面。而其次重要的內容是文字,所以擺第二,最後才是 layout
與其他屬性。
至於屬於同屬性的話不限制順序,例如 padding margin 順序調換沒有關係,因為找起來都很方便。只要維持一定的邏輯即可。
|
|
善用 sass map 管理變數
style 檔案變多了之後,相對的要管理的變數也會變得越來越多。
除了在命名時加上前綴之外,我們也可以利用 sass map 的方式來統一管理。而且 sass map 提供了一些很方便的 function 來操作,像是 map-get
map-has-key
等等,可以很有效地把變數 group 起來。很像 js 的 object。
以 z-index
來說,我們可以改寫下面的 code
|
|
用 map
的方式取值,看起來好像比較厚工一點,我們可以用 sass 的 function 包裝起來:
|
|
當然還有其他的應用像是 color
typography
等等,都可以搭配 sass map 的方式來操作。
如果你認為上述的方式跟用前綴的方式分類變數沒有什麼不同的話,不套用也沒關係,重構是為了讓之後的開發更舒服。
大量的巢狀 class
我的建議是不要超過三層,第一是易讀性非常低,再來很容易覆蓋到權重。
可以採用一些目前比較熱門的 css 命名規範如 OOCSS 或是 BEM,或者搭配兩者一起使用。
但最重要的一點是自己寫起來的感覺,不要讓規範箝制你了。
如果想要使用 scss 的巢狀功能方便閱讀,又不想要讓巢狀 class 覆蓋權重的話,可以使用 @at-root,@at-root 在編譯的時候會幫你把巢狀拆出來到 root。
另外可以使用 >
子元素選擇器來取代後代選擇器。
|
|
實際的 use case 如下:
|
|
以上的代碼好像沒有想像中的好看,等下可以搭配 mixin 把它進一步做簡化。
善用 Mixin 簡化程式
除了一般使用 mixin 來加入 prefixer
之外,mixin 能夠做的事情還有很多,這邊提出幾個方法給大家參考。
BEM mixin
BEM 的命名方式,如果一直手動 key 的話,感覺也挺麻煩的,而且 key 錯的機率也蠻高的,我們可以利用 mixin 來簡化他。
順便一提,如果你的專案已經套用了 postCSS
,可以使用 postcss-bem 來幫助命名。
如果你不喜歡他的命名方式,或是當前還無法套用 postCSS 的話也沒關係,我們可以自己做一個。
上面的 code 可以改成下面的形式:
|
|
這樣一來簡單的 BEM mixins 就製作完成了。注意到這邊我們使用 at-root
的方式來避免巢狀 class。
可以按照自己的喜好來調整命名方式,或者嚴謹一點對參數做一些處理(轉為小寫等等)、加入判斷式等等,或者今天你想要使用巢狀 class 的話可以加入額外的判斷參數。
|
|
util mixin
舉例來說,在設置 padding margin 的時候,我們常常會將上下或是左右的值設為一樣。寫久了難免會嫌麻煩,這時候就可以拜託 mixin 了。
|
|
這邊沒有寫得很嚴謹,你可以另外加入判斷式來保證輸入的值是合法的,類似的概念也能套用到 top left 設值上。
或是常常遇到的 clearfix。
|
|
child selector mixin
常常會遇到使用 child selector 的情境。我們可以用 mixin 進一步包裝起來。
|
|
這邊推薦 Family.scss,搜集了許多好用 child selector mixin。
p.s:我認為剛入門 CSS 的人還是從純 CSS 開始學習比較好,以免被 SCSS 的語法糖給寵壞了
善用 Comment
在缺乏 function 的 css 下,使用 comment 來解釋 class 更為重要。這邊提供一些,comment 的技巧。
註解不但方便自己閱讀,之後別人接手也會比較快理解這個 class 該如何使用、在哪個場景使用。
目錄
如果文件包含的 class 較多,可以考慮在文件最前面加入目錄,方便之後查找。
|
|
魔術數字、HACK、使用方式
|
|
CSS 結構
基本上分成幾個大方向:module
base
config
helper
module
module 資料夾裡存放所有模組化的元件,像是 button input modal 等等。如果元件拆得更細的話,可以再另外開資料夾,像是 button 有可能樣式比較多,這時候我們可以另外開一個 button
資料夾,裡頭存放所有 button 的樣式。
base
base 裡頭放置了像是 grid
normalize
reset
typography
等比較基本的架構。
config
存放變數跟 color 的地方,設定的內容統一存放在這個資料夾統一管理。
helper
存放客製化的 function 跟 mixin。
寫在最後
如果你有額外的時間,建議你還是可以去看看像是 postCSS、css-modules、webpack 等優秀的開源工具。
不然整天跟 CSS 打架總有一天會精神耗弱的XD。
做了一個DEMO,非常陽春。
如果你也想分享自己在前端跟 legacy code 奮鬥的過程,或是有更好的解決方案,歡迎在下面留言。
持續關注前端趨勢
這裡分享幾個覺得蠻優質的資源。
reference
why you should refactor your css