結構化CSS設計思惟

LESS、SASS等預處理器給CSS開發帶來了語法的靈活和便利,其自己卻沒有給咱們帶來結構化設計思惟。不多有人討論CSS的架構設計,而不少框架自己,如Bootstrap確實有架構設計思惟做爲根基。 要理解這些框架,高效使用這些框架,甚至最後實現本身的框架,必需要了解結構化CSS設計思想。
我不是前端專家,可是我想,是否必定要等成爲了專家才能佈道?那是否是太晚了。 因此我是做爲一個CSS的學習者,給其餘CSS學習者分享一下結構化CSS設計的學習心得。 我更多的是一個後端開發者,後端開發的成熟思想一定能給前端帶來新鮮血液。javascript

前言

CSS從根原本講就是一系列的規則,對Html(做爲內容標識和呈現)的風格化得一系列規則,所以,語法級別也就是兩個重要因素:選擇器和應用的風格。 簡單而超能。css

一開始,CSS很容易學習,容易上手。當咱們的網站成長爲企業級網站時,咱們的CSS開始成爲臃腫、重複和難覺得維護的一個混沌 。這種狀態在軟件開發中被稱爲Big ball of mud ,更爲常見的講法是麪條式代碼,是一種缺少良好架構和設計的表象。 解決這個問題的方法和思惟在後臺軟件開發中已是比較多的討論也相對成熟。同爲軟件開發的CSS開發,毋庸置疑,卻能夠這些借鑑思惟。html

面向方面

如前所述,CSS只是一系列規則,這是對CSS的初步認識,但咱們不能停留在這個認識。如同,咱們認識到全部物體都由原子組成,可是這個認識並不徹底可以替代化學在分子級別的研究。前端

這些規則必需要進一步分化,各自有不一樣做用和角色,不能平面化。表面上同是選擇器+風格化的CSS規則,根據它們的業務意義,應該劃分爲不一樣的類別或者方面 (Aspect 參考用詞Aspect-oriented programming)。java

這些方面分別是:git

  • 基本(元素)
  • 佈局
  • 模塊
  • 狀態
  • 主題

明確的分析你要寫的CSS規則屬於哪一個方面,在實現上區分這些方面並保持這樣的分離,
是往結構化走的重要一步。angularjs

基本(元素)規則和佈局規則

之因此把這兩類單獨提出來,是由於這是咱們平時理解的css彷佛就徹底只有這兩類。 咱們對那些劃歸這兩類的風格沒有異議,而對那些屬於這兩類的反而不太理解。 仍是先簡單瞭解一下這兩類自己的範圍。github

基本規則

是應用於基本元素級別的規則,做用於全局統一(默認)的風格。 最好的一個案例:CSS的重置框架reset.css以及bootstrap的改進方案normalize.css, 就徹底是基本風格規則,不包含任何其餘類型的規則。 雖然其做用和咱們平時項目中的基本風格不相同,用來理解基本風格的範疇是及其恰當的。編程

佈局規則

在咱們一開始談前端的結構化時,腦海中第一浮現的設計就是這個分層結構樹(或則分形的思惟):
頁面 Page => 佈局 Layout => 模塊 Module => 元素 Element 。bootstrap

一個頁面由佈局組成,每一個佈局局部由一個或多個模塊組成,一個模塊有n個元素組成,看上去簡單而完美,真正的結構化、模塊化。 然而,現實世界老是非線性的。在實際的項目中,嚴格的層次關係設計,遇到了各種「特例」須要打破這個結構。

好比,AngularJS是MVC架構,更準確一些,它是層次結構化MVC, 一個大的MVC又由其它幾個粒度更小的MVC組成, 特別是ui-router嵌套狀態和視圖把這個結構表達的更清楚。 從設計的思惟上,稱之爲分形更恰當。

當須要模塊與模塊之間的通訊和信息交流時,這種結構卻不能天然的支持,因而,有一個事件系統創造出來彌補這個缺陷。

之因此有這些「特例」,根本緣由就是分形思惟只適合在模塊這一級別,而不能往上擴展到佈局和頁面界別,也不能往下擴展到元素級別。

佈局就是佈局,應該做爲一個獨立的方面存在。
佈局規則中,咱們之關注組件之間的相互關係,不關心組件自身的設計,也不關心佈局所在的位置。
好比,用list(ol或者ul)作佈局用時:

.layout-grid{
    margin:  0;
    padding: 0;
    list-style-type: none;
}

.layout-grid > li {
    display: inline-block;
    margin: 0 0 10px 10px;
}

'list-style-type'和'display'的設置,咱們能夠明顯看出是佈局,'margin'和'padding'彷佛更像基本風格規則。 然而,從使用的目的來看,它們都是用於佈局的方面。

這個例子,咱們能夠看出對規則的劃分不是按CSS的技術特性,而是按業務特性:它們的做用,它們的「含義」。

模塊規則

這個類別含義是很明確清楚,只是強調一下,模塊能夠放在佈局的組件中,也能夠放在另一個模塊內部,是嵌套的,就是前面說的分形。

用class和語義標籤

咱們通常都用class來定義模塊,若是須要用到標籤則只能是有語義的標籤。如heading系列:

.module > h2{
    padding: ......
}

用subclass定義嵌套元素風格

如bootstrap的listgroup:

<ul class="list-group">
  <li class="list-group-item">First item</li>
  <li class="list-group-item">Second item</li>
  <li class="list-group-item">Third item</li>
</ul>

能夠看到,在list-group以外,它又另外定義了list-group-item來修飾li,而不是用如下方式省略掉子類的聲明和使用:

.list-group > li {
    
    ...
}

爲何要這樣? 能夠做爲一個思考題放在這。

狀態規則

狀態和子模塊有時候很類似,卻有亮的明顯區別:

  1. 狀態改變佈局風格或模塊風格
  2. 狀態大部分時候和Javascript相聯繫

這是什麼意思呢,咱們看看例子:

最經典的案例就是表單數據的有效性,通常都會引入class定義,相似is-valid;還有就是tab當前激活的狀態is-tab-active等。 前者,會改變表單的佈局:增長warning信息;後者,會改變tab模塊的顯示背景來代表當前tab是被選中的。
而以上兩個類也都會由javascript根據用戶操做,動態的添加到相應的DOM元素中去。

從狀態規則的兩個關鍵詞:改變和javascript,咱們能很明顯的看出它如其餘規則的區別,仍然重點在它的用途和業務含義。 它最重要的一個業務邏輯就是:狀態規則與時間相關,這也足以給它一個獨立的地位,與模塊規則的維度呈正交關係。

正交設計的延伸閱讀:

主題規則

主題是整個網站的風格全面的改變,能夠跨項目的才改一次,於是能夠在編譯階段進行 如bootstrap的customize用於這種場景;還有就是在一個項目以內也允許用戶動態改變。 這些絕對是與其餘規則不在一個方面,一定要獨立出來。

這類規則會涉及到全部其餘類型的規則,如:基本,模塊甚至佈局和狀態,雖然代碼量和工做量都較大,概念上卻很清楚,這裏就再也不展開。

基本規則和模塊規則的正交案例

在比較中,咱們看看類別之間的區別。

場景

好比說咱們網頁中須要一個表格來顯示一些信息,如iPhone 7的產品參數 https://www.apple.com/cn/iphone-7/specs/
爲它寫一個簡單的風格, 沒有任何問題:

table{
  width: 100%;
  border-collapse: collapse;
  border: 1px solid #000;
  border-width: 1px 1px;
}

td{
  border: 1px solid #000;
  border-width: 1px 1px;
}

以後咱們拿到一個新的需求,一樣用表格可是用來比較不一樣型號的產品的參數,如 https://www.apple.com/cn/iphone/compare/
爲了給客戶更好的體驗,須要對錶格風格作相應的調整,如相間隔的列用不一樣的背景色區分,表格的行之間須要實線間隔,而列之間則不要。 並且,這些修改不能影響以前信息表格的風格。

覆蓋方式解決表格的變體

直觀的解決方案,咱們引用一個類comparison來覆蓋以前的基本規則 :

.comparision {
  border-width: 0px 0;
}
.comparison tr > td:nth-child(even){
  background-color: #AAA;
}

.comparison  tr > td {
   border-width: 1px 0;
}

徹底依照新需求,作了三件事情: 1. 去標題的間隔線 2. 去掉了內容行之間的豎線間隔 3. 雙列背景灰顯。 點擊參看在線Demo

模塊方式解決表格變體

然而,用模塊的方式更爲清楚,更容易擴展。

基本風格(全局)

首先,與OO中提出基類的思惟相似,這裏咱們也提出公共的風格部分:

table {
  width: 100%;
  border-collapse: collapse;
}

信息表風格類info

而後,爲原來的信息表格寫出一個分支風格(OO中的子類)

.info {
  border: 1px solid #000;
  border-width: 1px 1px;
}

.info  tr > td {
   border: 1px solid #000;
   border-width: 1px 1px;
}

比較表信息類comparison

最後,爲新的比較表格寫出另一個分支風格

.comparison tr > td {
  border: 1px solid #666;
  border-width: 1px 0;
}

.comparison tr > td:nth-child(even){
  background-color: #AAA;
}

點擊參看在線Demo

比較分析

  • 覆蓋的方式中,儘管也用了類comparison,從設計的概念和使用的方式能夠看到,和模塊中的comparison仍是不一樣的,其業務的語義性弱化不少,以致於做爲開發者對其命名的準確程度都不太在乎了。 這是一個很很差的傾向。
  • 基本風格的widthborder-collapse確確實實是全局的風格,很少一點也很多一點
  • 結構很是清晰,風格之間沒有複雜的覆蓋關係: 好比比較表格中的border-width不會像前面的實現那樣,先 td{border-width: 1px 1px;} 而後又 .comparison tr > td {border-width: 1px 0;}覆蓋掉。 能夠想象在實際項目中,更多層次的覆蓋和更多規則的引入會帶來多少的複雜度和差錯率,你怎麼能準確的判斷究竟是那個規則再起做用?

狀態規則和模塊規則的正交案例

由於時間問題,這個案例須要到下次再整理了。

設計思惟回顧:

分形:

很是強大的思惟,對它自己彷佛有點陌生,當提及遞歸、全息理論是否更熟悉一些? 這些均可以看做是分形思惟的應用。

面向方面編程:

有時候又稱爲面向切面編程,曾經是個煊赫一時的名詞,如今好像沒怎麼提起,不是再也不適用而是思惟已經進入經常使用編程思惟,再也不須要強調了。

正交設計

和麪向方面有些雷同,在這重複也算一個強調吧。 另外,面向方面只能算正交設計的一種實現方式吧。

語義性

當你看到這「藍色 」兩個字時, 你腦子裏想到的是「藍色」仍是「紅色」?
語義設計就是要讓命名和內容一致,不要扭曲人性。 提高一個層次:咱們要讓代碼文檔化。

覆蓋和模塊

覆蓋是無結構,典型的「修補」編程法,甚至當不一樣需求被引入的先後順序不一樣時,會致使不一樣的代碼結構,隨意性太強。 模塊有設計,有業務含義,可維護性很強。

相關文章
相關標籤/搜索