談CSS模塊化【封裝-繼承-多態】


第一次聽到“CSS模塊化”這個詞是在WebReBuild的第四屆“重構人生”年會上,當時我還想,“哈,CSS也有模塊化,我沒聽錯吧?”事實上,我沒聽錯,你也沒看錯,早就有CSS模塊化這個概念了。之所以我把這個拿出來討論,是因為一個算是比較大的項目出現了一些重構上的危機,因此引發了我們對頁面重構中的CSS進行模塊化的思考。

首先,什么是CSS模塊化?在談CSS模塊化之前我們先看一下百度百科對模塊化的解釋:

“模塊化是指解決一個復雜問題時自頂向下逐層把系統划分成若干模塊的過程。每個模塊完成一個特定的子功能,所有的模塊按某種方法組裝起來,成為一個整體,完成整個系統所要求的功能。在系統的結構中,模塊是可組合、分解和更換的單元。”

我對上面一段話的理解是,模塊化就像我們玩樂高積木一樣,一個積木就是一個單元,可以通過組合不同的積木來搭建一個玩具模型。對於一個玩具模型,也 可以更換部分積木而迅速變成另一個模型。而CSS模塊化的關鍵,就是如何合適地構建這些單元,也就是一個一個的class,以及如何靈活運用這些單元來達 到我們所要的呈現效果。

說了一堆繁雜的話,連我自己都覺得乏味。作為一個熱愛編程的頁面仔,我想借用面向對象的三大特性來說明CSS模塊化——封裝、繼承、多態。

 

一、 封裝

談CSS模塊化【封裝 繼承 多態】

HTML代碼

<div class=”module-a”>

  <h3>標題1</h3>

  <p>描述文字</p>

</div>

<div class=”module-b”>

  <h3>標題2</h3>

  <ul>

    <li>列表</li>

    <li>列表</li>

    <li>列表</li>

  </ul>

</div>

CSS代碼

.module-a{.....}

.module-a h3{.....}

.module-a p{.....}

.module-b{.....}

.module-b h3{.....}

.module-b ul{.....}

.module-b ul li{.....}

.module-b ul li{.....}

.module-b ul li{.....}

封裝是實現CSS模塊化的最基本要求,封裝成的各個單元就是基本的CSS模塊,可靈活用於組建頁面的各種顯示樣式。

二、 繼承

談CSS模塊化【封裝 繼承 多態】

HTML代碼

<div class=” module module-A module-A-a”></div>

<div class=” module module-A module-A-b”></div>

CSS代碼

.module {.....}

    .module-A {.....}

        .module-A-a {.....}

        .module-A-b {.....}

    .module-B {.....}

        .module-B-a {.....}

        .module-B-b {.....}

繼承可謂是CSS模塊化的關鍵所在,由於html元素可以擁有多個類,而且根據優先級,后面定義的屬性可以覆蓋前面的,正因為這樣,繼承這個特性發 揮了巨大的作用。對於某些多數樣式屬性相同,僅有幾個不同樣式屬性的定義,可以用這個方法來實現。也可以在不改變某個通用樣式類的同時,用HTML調用復 合類,突出局部特例。

三、 多態

談CSS模塊化【封裝 繼承 多態】

HTML代碼

<div class=”module-A”></div>

<div class=”part-A ”>

    <div class=”module-A”></div>

</div>

<div class=”part-B ”>

    <div class=”module-A”></div>

</div>

<div class=”part-C ”>

    <div class=”module-A”></div>

</div>

CSS代碼

.module-A {.....}

.part-A .module-A {.....}

.part-B .module-A {.....}

.part-C .module-A {.....}

多態主要用於同一模塊在頁面的不同部分或者不同頁面之間呈現出不同的樣式。對於CSS的多態,一個很經典而且常用的例子就是導航欄。我們知道,導航 欄往往需要標識出當前頁面所在的導航鏈接。也就是說,對於導航欄的鏈接,通常有兩種形態,一種是常態,一種是高亮態,比如處於主頁時,主頁的鏈接就是高亮 態的,其他導航鏈接是常態的。這個時候,很多人喜歡在li上加上一個current類,用來把該導航鏈接設置為高亮態,但是我覺得這種方式並不理想。

為什么呢?因為對於結構一樣的導航欄,后台人員在處理時,往往是抽出成一個公共結構,然后各個頁面都引入這個結構。這對於后期的維護是相當有效的, 因為涉及導航欄的修改僅需修改一次即可,如果不這么做,那么修改的次數將會等於頁面的個數,而且容易出錯。對於這種情況,多態就可以很好地解決,因為我們 可以在每個頁面的body(或者其他地方)加上一個類來標識不同的頁面(此類可以不定義任何樣式)。那么,根據多態的特性,我們就可以為不同頁面的導航設 置不同的形態,同時又保持了導航鏈接的結構一致性。舉例如下:

HTML代碼

主頁:

<body class=”index”>

  <ul class=”nav”>

    <li class=”index”><a href=”#”>主頁</a></li>

    <li class=”page1”><a href=”#”>內頁1</a></li>

    <li class=”page2”><a href=”#”>內頁2</a></li>

  </ul>

</body>

內頁1:

<body class=”page1”>

  <ul class=”nav”>

    <li class=”index”><a href=”#”>主頁</a></li>

    <li class=”page1”><a href=”#”>內頁1</a></li>

    <li class=”page2”><a href=”#”>內頁2</a></li>

  </ul>

</body>

CSS代碼

//定義常態

.nav{.....}

.nav .index{.....}

.nav .page1{.....}

.nav .page2{.....}

//定義高亮態

.index .nav .index{.....}

.page1 .nav .page1{.....}

.page2 .nav .page2{.....}

這個就是多態的經典應用之一。

————————————補充部分————————————

joe哥指正,以上的這種對導航的處理辦法不太好,因為導航是一個公用組件,所謂公用,就是應該結構和樣式都是公用的,上面的那種方法沒有做到樣式上公 用,因為很明顯定義高亮態那里需要用到其他頁面的樣式類,而且joe哥提到可移植性的問題,如果這個導航搬到其他地方,那么就需要為新的頁面的body全 部都添加一個類(這個我真沒想過導航還可以給多個網站重用,我眼光太短淺了)。那么,究竟什么做才是比較主流的呢?加current,沒錯,就是加 current,這個被我一開始就否決的方法。那么又回到原來的問題,既然我們是引入同一個導航文件,那么current能加到哪里呢?joe哥提出一個 被我們都忽略了的方法,腳本!可以是js,可以是php,原來我們可以動態添加current類到導航去,驚訝吧!

好吧,我承認我有點過於興奮了,大伙兒看例子吧~

HTML代碼

<ul class=”nav”>

  <li class=”index” id="index"><a href=”#”>主頁</a></li>

  <li class=”page1” id="page1"><a href=”#”>內頁1</a></li>

  <li class=”page2” id="page2"><a href=”#”>內頁2</a></li>

</ul>

CSS代碼

//定義導航的樣式

.nav{.....}

.nav li.index{.....}

.nav li.page1{.....}

.nav li.page2{.....}

//定義高亮態

.nav li.current{.....}

JS代碼

function addCurrent(class,html_id){

  //class為增加的樣式類名,html_id為需要增加樣式類的html元素的id

  document.getElementById(html_id).addClass(class); //這里的class就是‘current’,addClass方法的實現我這里就不多說了,你可以用jquery或者別的,甚至自己寫

}

這種做法對於不同的頁面,或者新增的頁面,只需改js的一個參數即可,做到了把導航部分真正實現模塊化、組件化,公用的部分就應該公用到底,不留一 點余地。不過我還想說一點是,如果你的current(高亮態)不是單獨的換個背景顏色之類的,而是用雪碧圖這類的方法,每個導航鏈接的current類 都是不同的,那么以上的這種方法,貌似還有待改進。

————————————補充部分結束————————————

事實上應該指出,我這里討論的只是CSS模塊化的一部分,可以說是比較微觀的一部分。還有一些對CSS進行比較宏觀地划分模塊的說法,比如按頁面來划分,一個頁面或者說一個區域為一個模塊,比如像“幸福收藏夾”上所說的划分方法:

談CSS模塊化【封裝 繼承 多態】

網站的划分標准更大一些,是以網站的專題為模塊,不幸的是,很多專題的頁面風格都是類似的,導致各個模塊間存在大量的冗余代碼,這意味着對樣式的改動將會相當麻煩,一個地方的改動需要同時修改多個css文件。

表面上看,雖然對CSS模塊划分得細是一個不錯的想法,但並不是越細越好。現在的一些開源系統,如dedecms,甚至說YUI框架的1.0版本, 都流行一種做法,就是把CSS模塊細分成單屬性,比如把寬度960px定義為.w960,把清除浮動定義.clear,把字體綠色定義為.green等 等。

這樣做的好處是可以對頁面元素的樣式進行快速組裝,通過引入多個類便可以達到我們想要的效果。但是,這樣的做法會導致另外一個問題。大家想,這么做 與內聯樣式有什么區別?如果有一天,我們想要把多個地方的字體顏色由綠色改為紅色,那么我們要做的不是改動css的color屬性,而是把這些html元 素的class都由green改為red。請注意,我們的初衷是改變的頁面表現,但最終我們需要改變結構來達到我們的目的,這樣就做不到結構與表現的分離 了。

究竟怎么樣划分CSS模塊,又怎么來用這些模塊來組建頁面元素才是合適,其實很難找到一個標准,這不僅需要結合具體的頁面要求,還需要一定的經驗。

以上純屬個人見解,如有錯誤,歡迎指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM