CSS 架構指南
以命令式風格寫 CSS 會很快地導致下面的結果:
- 不夠清晰 —— 那些帶來了成噸混亂的東西,例如不清晰的依賴(難以刪除或者增加東西),
- 不可維護 —— 當在創建新代碼或者改善現有代碼的時候效率低下,
- 重復冗余 —— 使得代碼臃腫而且對性能有負面影響,
- 大量的存在于可擴展性,一致性以及對于新開發者的問題。
通常結果就是我們獲得了混亂的 UI 和 CSS。不用說都能體會到開發者心中的怒火熊熊!這還將導致亂七八糟的 UX。讓我們來看看為了防止上面的情況發生我們能做什么。
優先級
在選擇器之間的 優先級 戰爭通常反映了糟糕的代碼質量。擁有低的優先級將幫助更長時間地維護一個大型 CSS 項目的完整性和性能。
首先避免所有不必要的深層選擇器。為了給一個箭頭樣式,你真的沒有必要寫出這樣的選擇器:
.page-quick-sidebar-wrapper .page-quick-sidebar .page-quick-sidebar-chat .page-quick-sidebar-chat-user .page-quick-sidebar-chat-user-messages .post.out .message .arrow {
}
我們可以使用更有意義的選擇器例如 .message-arrow { … } 并且用它來代替 .arrow?或者只需要給 .arrow 寫樣式如果只有一個箭頭需要給樣式?
在大多數情況下會出現 SASS/SCSS 嵌套陷阱。嵌套不應該多于三層。停止趨向于使 SASS 嵌套跟 html 嵌套一致。別嘗試使 CSS 選擇器視覺上層次分明(這看起來很美麗但導致了維護開銷)。為我們的利益著想,別基于他們在哪里或者他們怎么表現而是基于他們是什么來賦予樣式(位置獨立性)。
創建選擇器
ID 比類名強了好幾個數量級。因此你不能輕易地用類名選擇器重載 ID 選擇器的樣式。避免將 ID 作為樣式的鉤子,但如果你為了其他東西(例如 JS 鉤子)需要也可以使用它們。當創建選擇器時似乎類就是最好的解決方案。那標簽選擇器呢?只有在重置或者應用普遍樣式時你才能使用標簽。使用 !important 并不是一個安逸的實踐,除非「你在使用的時候不會憤怒」。它完美適配你的通用類。
命名
命名約定有益于立刻理解一個特定的樣式屬于哪一個類別以及它在總體頁面里的職責。
這是一些適合應用于任何命名約定里的規則:
- 基于它是什么而不是它看起來或者表現起來怎么樣來命名某個事物.
- 通常來說,有更長的類名比更復雜的優先級更好。
在大多數情況下給類和 id 加前綴是不錯的。使用前綴和/或命名系統幫助區分框架和自定義類/id。更重要的是通過這樣做你可以輕易地避免命名沖突(例如你希望實現一個日期選擇器,它添加了全局類如 .next 或者 .prev。如果你之前已經使用了這些類名,會發生什么?)所以怎么使用前綴?
- .u-hide-text (“u”表示它是一個有特定目的的通用類。它會在很多地方使用而且不應該被擴展。通常你希望確認通用類會贏得優先級戰爭。 Therefore using !important it’s not bad practice for that case.因此在這個例子中使用 !important 是個不錯的選擇。)
- .l-main-nav (“l”指布局或者組件類。用于把模塊組合成組件以及將他們定位在頁面中)
- .b-main-nav (“b”前綴能被應用在主塊或是模塊容器中)
- .js-header-animate (“js”指這個類只能被 JavaScript 使用。這避免了基于類名的意外破壞行為或測試。)
BEM
一種更流行的命名約定是 BEM。通過使用這種命名約定你會自動地以一組獨立的模塊“而不是我怎么賦予這個頁面樣式”來考慮布局。一些常見的 BEM 規則:
- 你希望只使用類來構建選擇器。在大多數情況下你的選擇器是一個獨立而有意義的類。
- 類名從塊/模塊的名字開始,下一個是元素的名字(緊接在兩個下劃線之后),最后是修飾器的名字(在兩個破折號之后)。例如 .main-nav__item?—?current。
- 修飾器既能應用在塊上也能應用在元素上。
- 不能有元素出現在它的塊之外。
- 你可以在它的塊內嵌套元素,但是在這種情況下不要寫出像這樣的選擇器: .block__element1__element2。而是始終使用:.block__element1 .block__element2。
- 塊是獨立的,只會共享大部分普遍樣式(重置和一些基礎樣式)。這減少了代碼量,以及使其可重用。
- 你不希望直接在塊或者模塊上直接應用布局樣式。這就是為什么我們想要使用布局類的原因。
多虧了 BEM 我們現在有了:
- 模塊化 CSS 代碼。這使得 CSS 很容易地轉換到 React 世界,在這里中你經常希望擁有每一個組件單獨的 css 文件;
- 非常低的優先級;
- 解耦 HTML 結構和 CSS;
- 提高可讀性(你能夠在看 HTML 的時候知道更多關于 CSS 的東西);
- 不再有命名沖突(單獨的模塊幫助避免了把 CSS 放在全局范圍內);
- 對于如何在一個塊中命名一個新變量的清晰規則;
- 級聯繼承樣式不再有問題(在你不想要的地方出現意外的樣式泄漏);
- 減少類之后更小的 HTML 以及令 HTML 可重用。
相關鏈接
?ukasz Klis??—?To BEM, or not to BEM(波蘭語)
移動優先
為什么這個概念是有益的?首先通過實現移動端版本你會強迫去考慮內容層次。你希望以最可行的方法(簡單而高效的解決方案)提供最需要的功能和內容。這對于桌面版本來說是有正面作用的。其次,增加比刪除要更容易。
編寫媒體查詢
使用預定義的斷點(像 bootstrap 使用的那樣)對于柵格管理來說很好但是對于改變模塊樣式來說不是必要的。添加一些自定義斷點完全沒有壞處。我們希望我們的 webapp 在寬泛范圍內的解決方案中都可以適應地很好。而不只是對于那些使用柵格框架定義的。通常來說使用“min-width”斷點是更優雅的方案。盡量避免只使 用“max-width”斷點。通過這樣做你會得到更少的代碼,更少的重載和更少的 !important 聲明。
組件,模塊和元素
盡可能快的嘗試建立可獨立的模塊和組件(模塊的集合)。當創建類似的模塊時記得以適當的 CSS 方式使用 DRY 原理。詳見 這里 和 這里。
模塊,組件和元素之間的區別在哪里?
組件是模塊的集合。在大多數情況下它會跟布局類處在相同的抽象層次。
模塊是元素的集合。應該可重用而不依賴于其他模塊。
元素是不能單獨使用和需要父級實體的代碼片段。
例:頁眉是組件。它包括了模塊——導航欄和 logo 模塊。 Navigation has items elements.導航欄有項目元素。Logo 有圖片和文本元素。
文件和目錄結構組織
為了創造可維護的 CSS 架構我們需要比一個巨大的 main.css 文件和第三方目錄更多的東西。下面的描述主要基于 SMACSS 概念。
首先我們將需要一個預處理器用于編譯 CSS 文件(在每一次保存之后),生成依賴和教新的 CSS 技巧。出于 debug 需要我們不希望在開發環境中壓縮文件。
依賴
我們希望以下面的順序加載我們的 CSS:
- 第三方樣式(框架,插件樣式)
- 下一個是我們的通用部分。我們希望加載所有的變量,mixins 和其他助手(類,占位符)。
- 如果我們沒有使用一個提供了 CSS 重置的框架,那么我們絕對希望引入 normalize.css(或者其他類似的) 加上我們自定義的重置和基礎樣式。
- 最后我們可以引入布局和模塊樣式。
項目結構
為了確保布局一致性我們應該努力保持(只保持)全局范圍共享 css。
— 第三方 全局范圍使用的工具
— 基礎 CSS 重置(例如 normalize)和 基礎樣式。“基礎樣式是默認的。他們幾乎都是清一色的單元素選擇器但也可以包括屬性選擇器,偽類選擇器,后代選擇器或者同級選擇器。本質上來說,一個基礎樣式意味著不管這個元素在頁面上的何處,它都應該看起來像這樣。”
— 依賴 全局使用的:變量,度量,顏色,排版和表單樣式,SASS mixins 和函數,debug 工具。
— 模塊 是可重用的,在我們的設計中模塊化的部分。每一個模塊總是使用一個文件。
— 布局 模塊的容器。布局將頁面劃分成多個部分,并使一個或多個模塊處在適當的位置,將它們定位在頁面中。這是唯一一個你可以添加 margins,width,height 等等的地方。所以布局與模塊一起合作,但是模塊是獨立的單元而且可以在任何上下文里使用。
— 狀態 是用來描述我們的模塊或者布局在特定狀態下的將會如何顯示的方式。是隱藏的還是展開的?是激活的還是未激活的?是關于描述一個模塊或者布局在更大或者更小的屏幕里如何顯示的。還是關于描述一個模塊在不同的視圖中例如主頁或內頁里應該如何顯示。
來自:http://www.zcfy.cc/article/css-architecture-guidelines-1099.html