iT邦幫忙

DAY 29
3

Sass3.3 & CSS設計模式系列 第 30

Sass教學 (29) - SMACSS - Module Rules


影片教學請點選下圖連結↓

以下文章同步於Github

程式碼連結
SMACSS - Module

進入主題
Module意思是一個獨立的CSS組件或單一元素, 被設定成模組的CSS組件會是獨立的,
不該綁定在父容器、ID選擇器、HTML元素,並同時能靈活套用至各頁面上`。

不要將CSS直接指定ID與HTML元素
這裡提出SMACSS所寫的範例Code,
如果今天你很確定在.fld裡面只會有一種span樣式這樣寫是ok的:

//HTML結構
<div class="fld">
    <span>Folder Name</span>
</div>

//CSS樣式
.fld > span {
    padding-left: 20px;
    background: url(icon.png);
}

但假使你不能保證之後還會增加其他span樣式的話,像是這樣子:

<div class="fld">
    <span>Folder Name</span> 
    <span>(32 items)</span>
</div>

你不就必須再回頭修改你的CSS設定?
其他HTML頁面早已套用舊CSS的話,
那更可怕的是你還必須回頭一一把所有的HTML修改為新架構,
專案越來越大時,程式碼彈性就會變得越來越低,
所以SMACSS會建議這樣寫:

//HTML結構
<div class="fld">
    <span class="fld-name">Folder Name</span> 
    <span class="fld-items">(32 items)</span>
</div>

//CSS樣式
.fld{..}
.fld .fld-name{}
.fld .fld-items{}

所有樣式都指定class給HTML TAG,
這樣設計上有兩個好處:

1.不受HTML的全域樣式控制
如果你寫.fld span{..}的話,
意思即是在.fld的範圍內,
你的span都被該CSS設定所綁定住了,
假使今天.fld裡面要新增不同樣式的span,
你就只能用更高的權重來覆蓋掉他的樣式,
例如.fld span.box{..},
這樣子你的程式碼就會因覆蓋緣故變得更加得臃腫,

但如果你直接指定class給該元素的話,
像是
好處是新增其他的span標籤就變得很乾淨, 也解放了span讓它仍保持單純的inline排版元素,
新增class在span上都變得相當容易,
你也不用再去頭痛權重覆蓋的問題。

2.網頁SEO、HTML語意化更動變得更加靈活
像是上面的HTML結構是長成這樣。

<div class="fld">
    <span class="fld-name">Folder Name</span> 
    <span class="fld-items">(32 items)</span>
</div>

假設在某頁上,.fld的區塊在這頁佔得權重較高,
我們便能夠很輕鬆地把它改成下面的HTML結構:

<article class="fld">
    <h3 class="fld-name">Folder Name</h3>
    <span class="fld-items">(32 items)</span>
</article>

看到這裡,
相信你就知道為什麼SMACSS不建議你直接將CSS樣式綁定在HTML tag或ID上面了,
原因自然是因為直接寫在class上,不論是要更動HTML結構或新增CSS樣式都變得更加靈活。

子模組(Subclassing Modules) 設計
在設計CSS模組時,
時常會遇到樣式臨時變動或新增的需求,
這時候就可以參考SMACSS的Subclassing Modules的觀念,
我們先來瀏覽下面的程式碼:

//設計一個.pod區塊,裡面的文字欄位佔了50%寬度
.pod { 
    width: 100%; 
}
.pod input[type=text] { 
    width: 50%; 
}

//設計到一半後,上面的模組要套用到#sidebar,且裡面input要改成100%時
//只好寫成下面這樣子來覆蓋上面模組
#sidebar .pod input[type=text] { 
    width: 100%; 
}

這樣子寫法是相當不好的,
第一如果我今天不是要放在#sidebar,
而是要放在.main的區塊,設定也是裡面文字欄位是100%寬,
那你的Class也會因此越來越肥,如下程式碼:

#sidebar .pod input[type=text],.main .pod input[type=text] { 
    width: 100%; 
}

更糟糕的事情是,
你的程式碼可讀性也會變得非常差,
這裡來舉個例子:

//寫好此模組設定
.pod { 
    width: 100%; 
}
.pod input[type=text] { 
    width: 50%; 
}

//寫到第三百行
//#sidebar裡面要用到.pod區塊,所以這樣子寫
#sidebar{..}
#sidebar a{..}
.#sidebar .pod input[type=text]{width: 100%; }


//又繼續寫了三百行
//.main又要設定.pod裡面文字欄位要100%時,就又必須回去追code,
//然後猶豫到底要放到最上面點.pod模組區塊,還是到#sidebar把class合併起來
//最後決定先在#sidebar那裡合併程式碼
.main{..}
.main ul{..}
.main li{..}

//隔天再來寫code,繼續寫了三百行,又有一樣東西要設定,
//就還得回想當初是在哪裡有寫過這行程式碼,還是不管它直接寫在.block裡面。
.block{}
.block .pod input[type=text] { width: 100%; }


//專案第六十天你已經不知道你的CSS在寫些什麼鬼東西了

為了避免這樣的事情發生,
SMACSS的Subclassing Modules 建議你這樣子寫:

//CSS樣式
.pod { 
    width: 100%; 
} 
.pod input[type=text] { 
    width: 50%; 
}
.pod-constrained input[type=text] { 
    width: 100%; 
}
.pod-callout { 
    width: 200px; 
}
.pod-callout input[type=text] { 
    width: 180px; 
}
//HTML結構
<div class="pod pod-constrained">...</div>
<div class="pod pod-callout">...</div> 

兩行HTML都載入了.pod的class,
讓網頁版型先吃到預設樣式,
如果今天裡面的按鈕要改成100%,
那就再增加子模組class.pod-constrained,
這樣就能夠覆蓋掉.pod的input設定。

如果你的.pod的寬度必須調整,
那你也可以透過子模組class.pod-callout來覆蓋.pod,

Subclassing Modules利用CSS覆蓋、HTML可以載入多個Class的原理,
讓我們只要回到模組的class新增子模組滿足條件覆蓋樣式。
這樣子整個邏輯就可以都依照著.pod的模組區塊來延伸子模組,
不會又因為其他頁面的class區塊更動了模組設定而猶豫該怎麼寫。

單一元素模組設定
這個是我自己補充模組的部分,
當我還是菜鳥的時候,我會這樣來設計一個按鈕:

//HTML結構
<div class="row">
    <input type="button" value="">
</div>

//css程式碼
.row{
    text-align: center;
}
.row input{
    css按鈕樣式程式碼
}

這樣的程式碼確實能吃到樣式,
但它的彈性就會變得非常非常得差,

如果.row這個div裡面又要放其他input元素,
而且樣式完全不一樣,你不就得CSS和HTML的架構都得全改,
更別說專案在執行過程中,你已經設計好幾百頁HTML,
結果又必須重新回頭去修改HTML設定,
所以請盡量不要直接綁HTML tag,
每次美術和我說它不會改畫面,
那裡就一定只會有那個元素,
我也就很開心得下了這樣的語法, 但到後來改得機率都是高達99.9999%....OTZ,
於是乎我就都改寫成這樣的寫法了:

//HTML結構
<div class="row">
    <input type="button" class="btn" value="">
</div>

//css程式碼
.row{
    text-align: center;
}
.btn{
    css按鈕樣式程式碼
}

你可以從上面的程式碼看得出來,
我的按鈕直接指定一個class樣式,
不依附在父元素上面,
所以今天你要在各個頁面上套用這個按鈕樣式時,
就只要在input上面加上btn的class就好。

這樣就可以做到SMACSS所提倡的觀念,
也就是Module要設計為獨立的樣式, 不該綁定在父容器、ID選擇器、HTML元素,並同時能靈活套用至各頁面上。


上一篇
Sass教學 (28) - @each+Sass Maps批次新增各元素樣式
下一篇
Sass教學 (30) - SMACSS - State Rules
系列文
Sass3.3 & CSS設計模式46

1 則留言

我要留言

立即登入留言