1. 程式人生 > >CSS模組化(六) 模組化設計

CSS模組化(六) 模組化設計

6. 模組化設計

6.1 樣式的作用域──頁面重構中的模組化設計(一)

模組化設計我已經提過很多了,都是跟模組化相關的,不過之前一直沒有講到具體實現方面的內容,只是一些思維。這次重點講一下實現方面的內容,權當到目前為止我對模組化的一些總結整理。

要做好模組化,我覺得理解好樣式的作用域是很重要的。寫過程式的同學應該都知道,變數是有作用域的(不知道的同學自己去問谷歌,這裡就不作解釋了),樣式的定義也同樣存在著作用域的問題,即定義的作 用範圍,很容易就能理解,如下面的p的作用域:

 CODE:

/*作用域:全域性*/ p{text-indent:2em;}

 CODE:

/*作用域:.demo這個類中*/ .demo p{color:#000000;}

    樣式選擇器的優先順序是學習樣式的基礎知識,一起簡單回顧下:

● 標籤的權值為0,0,0,1

● 類的權值為0,0,1,0

● 屬性選擇的權值為0,0,1,1

● ID的權值為0,1,0,0

● important的權值為最高1,0,0,0

使用的規則也很簡單,就是選擇器的權值加到一起,大的優先;如果權值相同,後定義的優先。雖然很簡單,但如果書寫的時候沒有注意,很容易就會導致CSS的重複定義,程式碼冗餘。從上面我們可以得出兩個關鍵的因素:

1權值的大小跟選擇器的型別和數量有關

2樣式的優先順序跟樣式的定義順序有關

瞭解樣式的權值後有什麼作用呢?比如可以這樣用:舉一個最簡單的例子

CODE:

body{color:#555555;}.demo{color:#000000;}

CODE:

<p>這裡的文字顏色受全域性定義的影響</p>

<div class="demo"><p>這裡的文字顏色受類demo定義的影響</p></div>

<p class="demo">這裡的文字顏色受類demo定義的影響</p>

知道了樣式的權值,你就知道上面例子的表現是怎樣的了。進一步的應用,就是模組化了。

再來說說作用域,相信大家很容易就會想到全域性公共這些詞,關注過模組化的同學應該都知道,網上說得最多的一種模組化,就是像 headerfooter這樣的以大區域劃分。在去年

web標準交流會(頁面重構合理化討論)上,克軍提出了樣式的三層架構”——公共規則層、公共模 塊層、專案層。這些都有它們適用的範圍,而且最大的優點是容易理解和應用。這裡也不再作重訴了,上面已經講過。

我在這一塊的劃分上,有點類似克軍的樣式的三層架構,有一點小的差別,我是以作用域來分的:公共級(全域性)、欄目級 (區域性公共)、頁面級。如何劃分這個作用域呢?很簡單,全域性的global就是公共級的;只在欄目中用到的區域性global是屬於欄目級的;隻影響單個頁面的就是屬於頁面 級的了。

最後幾點要特別注意的:

除了標籤選擇器之外,哪些類是使用於公共級、欄目級中的,如

 CODE:

.tx_hit{color:#FF0000 !important;}

的適用範圍是公共級的,應該放於全域性的定義中。但,如果它隻影響於某個欄目,那麼就應該把它放於欄目級的作用域中。

● 標籤選擇器一般屬於欄目定義,有時會用於公共級作用域中,除了最基礎的reset之外,應儘可能少使用在公共級定義中

● 可繼承的屬性定義使用時須注意影響的範圍,特別是在標籤選擇器中使用時

● 同類選擇器無加權

接下來的內容就是以這個為基礎的,希望大家能理解樣式的作用域,對於後繼內容的理解會很有幫助。

6.2 欄目級作用域──頁面重構中的模組化設計(二)

在《樣式的作用域── 頁面重構中的模組化設計(一)》中,我將樣式的作用域分為了三個部分:公共級(全域性)、欄目級(區域性公共)、頁面級。公共級(全域性)容易理解,即影響站點中所有頁面。簡單解釋下欄目級(區域性公共)和頁面級:

頁面級

可分為兩種情況:在多個頁面間,頁面級作用域指標對某一單獨的頁面定義;在同一個頁面中,頁面級作用指標對某 一標籤的定義。它將決定最終的頁面效果。

欄目級(區域性公共)

介於全域性與單個頁面之間的一個作用 域,影響一個欄目(或某區域)。通常以某一類選擇符做為開始,以包含選擇符的方式將樣式定義限定在某一區域中。

 CODE:

/* 隻影響demo這個區域 */

.demo a{...}

.demo p{...}

.demo .title{...}

需要消化下的內容,決定一個樣式定義是屬於哪個作用域的因素有以下兩點:

樣式定義所在樣式檔案中的位置。(同樣的一個定義,放在不同的位置,所影響的範圍會有所不同。)

HTML中繫結demo這個類的標籤位置。(同樣一個類,繫結在body標籤和繫結在頁面中某個標籤上,所影響的範圍也會不同。)

在一個站點中,可能會分為幾個不同的欄目,同一個欄目中,一般風格會保持一致。而不同的欄目間,相似的風格則不一定會相同。即使是全站通用的模 塊,如翻頁,也可能會因為欄目的不同而會有一些差異,比如連結的顏色等等。使用欄目級的樣式定義,能很好的減少程式碼的冗餘,提高模組的複用性。

另外需要在思維上注意的一點,以作用域劃分,並不意味著有著對應的檔案,可能有些同學會習慣的以為一個作用域就應該對應著一個檔案。比如一個小的 欄目,可能只有兩三個頁面,這時我們就不一定需要再把欄目級的定義單獨出來一個檔案,而是與頁面級的定義一起放在一個檔案裡,像這樣:

CODE:

/* S 欄目級定義 */

.class{...}

/* E 欄目級定義 */

/* S 頁面級定義 */

.page{...}

/* E 頁面級定義 */

6.3 繼承──頁面重構中的模組化設計(三)

前面我們瞭解了樣式的作用域的分類欄目級作用域。在權值中,還有一個很重要的因素,需要做下補充,起因是這樣的,有個同學在CSS森林群裡問了個問題:根據樣式權值兩個關鍵的因素

權值的大小跟選擇器的型別和數量有關

樣式的優先順序跟樣式的定義順序有關

可以知道,如果10個標籤選擇器的權值應該比一個類選擇的權值高,像這樣:

 CODE:

div div div div div div div div div div div{color:blue;}

.c10{color:red;}

CODE:

<div class="c1">

  <div class="c2">

    <div class="c3">

      <div class="c4">

        <div class="c5">

          <div class="c6">

            <div class="c7">

              <div class="c8">

                <div class="c9">

                  <div class="c10">

                     <div>這段文字是什麼顏色?</div>

                  </div>

                </div>

              </div>

            </div>

          </div>

        </div>

      </div>

    </div>

  </div>

</div>

先別急著看答案 ,分析下。意料之中?如果這樣 呢?

CODE

div{color:blue;}

.c10{color:red;}

是不是跟想的不太一樣?難道前面所說的權值是有問題的?前面講的權值並沒有問題,不過漏了一個重要的規則: 繼承的權值小於 0,0,0,1

樣式的繼承

指被包在內部的標籤將擁有外部標籤的樣式性質。

繼承最大的意義在於可以減少重複的定義,比如要定義整個頁面的文字顏色,只需要定義bodycolor樣式,body裡的所有標籤都會繼承 bodycolor定義。是不是很方便?方便是相對的,當你想要為body內部分標籤定義另一種文字顏色時,繼承也許會成為增加重複定義、降低效能的禍 首。

並不是所有的樣式定義都具有繼承的性質,整理了一下常用有繼承性的定義, 這些定義在使用的時候要比較注意。

簡單分析下上面的例子,最後一部分的程式碼:

 CODE

<div class="c10">

    <div>這段文字是什麼顏色?</div>

</div>

當定義了c10後,根據權值,類定義的權值是0,0,1,0,應該是比div這個定義0,0,0,1要高的,但由於div是直接定義到標籤上的, 比起從c10的定義中繼承來的定義權值更高。稍微改下就清楚了:

CODE:

<div class="c1">

  <div class="c2">

    <div class="c3">

      <div class="c4">

        <div class="c5">

          <div class="c6">

            <div class="c7">

              <div class="c8">

                <div class="c9">

                  <div class="c10">

                     <p>這段文字是什麼顏色?</p>

                     <div>這段文字是什麼顏色?</div>

                  </div>

                </div>

              </div>

            </div>

          </div>

        </div>

      </div>

    </div>

  </div>

</div>

修改後的例子 可以看到,p標籤繼承了c10的定義,顯示為紅色。因此,在使用標籤選擇器的時候,應特別注意它的作用域,個人的建議是,除了最基本的reset之外,在 公共作用域中最好不要使用標籤選擇器,在欄目級作用域中也應儘可能的少用。

常用有繼承性的樣式定義:

● text-indent

● text-align

● layout-flow

● writing-mode

● line-break

● white-space

● word-wrap

● list-style

● list-style-image

● list-style-position

● list-style-type

● font

● font-style

● font-variant

● font-weight

● font-size

● line-height

● font-family

● color

● text-transform

● letter-spacing

● word-spacing

6.4 模組化的核心思想──頁面重構中的模組化設計(四)

有不少同學覺得前面的內容過於簡單了,對於樣式的作用域的分類欄目級作用域繼承等內容的確十分基礎,不過基礎還是很重要的。下面就一起進入這個系列真正的主題——“模組化吧。

早在Qzone4.0的頁面架構中已經在專案中開始摸索提高程式碼複用的方法,只不過當時並沒有很清晰的認識到模組化這個思想。從去年的《從宜家的傢俱設計 講模組化》開始,模組化成了我主要的一個學習方向。藉著無數的提問、思考、討論,漸漸形成了一個比較清晰的、較為完整的方案。後面的內容,更多的是出於我在實際項 目中總結出來的方法,雖然已經儘可能為出現的問題提供瞭解決方法,不過還是少不了會有些我沒遇到過或沒考慮到的,歡迎各位指出。

首先來了解下頁面重構中模組化的核心思想:HTMLCSS通過一定的規則進行分類、組合,以達到特定HTMLCSS在特 定範圍內最大程度的複用。有三個關鍵詞:規則特定範圍最大程度的複用。怎麼理解呢?

規則

編寫模組時需要遵循的規範

特定範圍

模組可使用的範圍。與樣式的作用域有關,大部分模組的使用範圍僅僅是某一個欄目或站點。

最大程度的複用

做最少的修改即可重複使用。很多同學都把複用理解成不用修改的直接使用,但在頁面 製作中,由於實際的專案環境,基本是不可能做到一個模組走天下的。不同的欄目會有不同的需求,大家應該都多少有所體會,我就不多講了。

從實際出發,才能最終服務於實際。我們知道一個HTML標籤可以繫結多個樣式,所以我們可以這樣去定義一個模組:

CODE:

<div class="class-a class-b class-c">

    ...

</div>

不少同學已經知道這個方法了,而且還很形像的稱之為拼樣式。這樣的定義很容易引出其它的問題,比如樣式類的個數多少個適合?樣式類如何命名? 等等。下面講下我的方法,從前面我們學到的樣式作用域及模組化的核心思想,我們可以把樣式進行一個分類,像這樣:

 CODE:

.mode-a{/* 定義一個模組 */}

.type-a{/* 模組中的差異化定義 */}

.mode-name{/* 針對單個模組的個性化定義 */}

CODE:

<div class="mode-a type-a mode-name">

    ...

</div>

上面的“mode-a”,我稱它叫為基類“type-a”擴充套件類“mode-name”模組名,作用分別是:

基類

(基礎樣式)模組的基礎表現。包含了模組中大部分的狀態。

擴充套件類

(擴充套件樣式)用於對使用基類的模組進行小範圍的修改

模組名

模組在某一作用域中的唯一名稱。

這裡有一個簡單的例子 可以幫助理解。

也有同學主張用ID去表示模組名,我認為這種方式擴充套件性比較差,而且很容易與開發的ID衝突,不過也不失為一個方法。

6.5 基類、擴充套件類──頁面重構中的模組化設計(五)

基類擴充套件類是這個系列的主要內容,上一篇《模組化的核心思想──頁面重構中的模組 化設計(四)》中只是簡單提了一下,我們再深入的來了解下它們。

一般所使用的模組化的方法,就是以某一個類做為定義的開始,比如:

CODE:

/* S 圖片列表 */

.pic_lists li,

.pic_lists li img{float:left;width:122px;height:122px;margin-bottom:8px;}

.pic_lists li{list-style:none;margin:0 0 0 6px;text-align:center;}

.pic_lists li .pic{display:block;border:1px solid #476081;}

/* E 圖片列表 */

/* S mtv列表 */

.mtv_lists{width:930px;height:130px;}

.mtv_lists li,

.mtv_lists li img{float:left;width:120px;margin-bottom:8px;}

.mtv_lists li{list-style:none;margin:0 10px 0 0;text-align:center;}

.mtv_lists li img{height:90px;border:1px solid #476081;}

.mtv_lists li .pic{display:block;width:120px;height:90px;margin-bottom:8px;}

/* E mtv列表 */

這個例子:兩個列表模組 。這種方式是比較常見的,可以很好的將一個模組獨立出來。如果使用新學習到的方法來寫這兩個列表模組,應該是怎樣?

基類(基礎樣式)模組的基礎表現。包含了模組中大部分的狀態。也就是說,當出現多個類似的模組時,基類包含了這些模組的大部分的效果(或者理解為公共的部分),在基類的基礎上,我們可以通過新增很少的程式碼 ——擴充套件類,來達到所需要要效果。像這樣:

CODE:

/* S 列表 基類 */

.mode_lists li,

.mode_lists li img{float:left;width:122px;margin-bottom:8px;}

.mode_lists li{list-style:none;margin:0 10px 18px 0;text-align:center;}

.mode_lists li img{border:1px solid #476081;}

/* E 列表 基類 */

/* S 圖片列表 */

.pic_lists li,

.pic_lists li img{height:122px;}

.pic_lists li{margin:0 0 8px 6px;}

.pic_lists li .pic{display:block;border:1px solid #476081;}

/* E 圖片列表 */

/* S mtv列表 */

.mtv_lists{width:930px;height:130px;}

.mtv_lists li,

.mtv_lists li img{width:120px;height:90px;}

.mtv_lists li .pic{display:block;margin-bottom:8px;}

/* E mtv列表 */

可能你會覺得這樣的樣式不就多寫了,還得把原先的模組類變成兩個。的確不是所有的模組都值得這樣去做,於是我們可以得到一種偷懶的作法,把其 中一個模組直接變成基類。對於經常會被使用的模組,像圖片列表、播放列表等,這種寫法在程式碼的複用和效率會有一定的提高。一般情況下只需要做下簡單的修改 即可應用,來看一個複雜些的例子:

一個帶頭像的訊息列表(A

看看這兩個圖,在腦中先想想如果是你,你要怎麼實現。……5分鐘過去了……差不多有方案了,按上面的思路,基類是包含了大部分的效果的,也就是說 基類應該能滿足大部分效果的需要,兩個模組間差異的地方,可以通過擴充套件類來完成。當然前提是這兩個模組有能找到類似的點,能夠形成基類。

在這兩個模組中,我們不難看出,A模組和B模組在資訊的部分是很類似的,雖然B模組的列表不需要A模組的評論部分,但這並不影響B模組的表現。所 以我們可以把這兩個模組看成的類似模組。另個,以哪個為基類呢?從滿足大部分效果這個要求來看,很明顯A模組做為基類是要比B模組做為基類更合適的,如果 用B模組做基類,那麼需要寫更多的擴充套件類來滿足A的需要。另外還有一個重要的點,之所以選擇A模組為基類,是因為A在欄目中被更多的頁面使用。

OK,來看看A模組怎麼實現(樣式部分):

 CODE:

/* S 訊息 基類 */

.mode_message{position:relative;padding:8px 3px 8px 48px;

border-bottom:1px solid #DAECF6;_zoom:1;line-height:1.3;}

.mode_message .user_info{position:absolute;left:3px;top:10px;}

.mode_message .user_info .pic img{width:35px;height:35px;}

.mode_message .mode_message_cont{color:#797979;

word-break:normal;word-wrap:break-word;}

.mode_message .mode_message_cont .info{display:block;zoom:1;}

.mode_message .mode_message_cont .info .music_name{color:#22639B;}

.mode_message .mode_message_cont .info .op_music{display:none;}

.mode_message .mode_message_cont .info:hover .op_music,

.mode_message .mode_message_cont .info.hover .op_music{display:block;position:absolute;right:5px;top:7px;

background-color:#FFFFFF;}

.mode_message .msg{padding:2px 0;word-break:normal;word-wrap:break-word;}

.mode_message .mode_message_cont .op{margin-bottom:3px;}

.mode_message .time{display:inline-block;*display:inline;*zoom:1;font-size:10px;}

.mode_message .msg .p_zt_l,.mode_message .msg .p_zt_r{display:inline-block;*display:inline;*zoom:1;

width:13px;height:8px;background:url(img/_g_other.png) no-repeat -17px -17px;

vertical-align:text-middle;*vertical-align:middle;}

.mode_message .msg .p_zt_r{background-position:0 -28px;}

.mode_message .write_back .cont{margin-bottom:2px;padding:5px;background-color:#EAF6FA;_zoom:1;}

.mode_message .write_back .cont .cont{border-left:1px solid #ABCFE1;}

.mode_message .write_back .cont .zt{*overflow:hidden;}

.mode_message .write_back .cont .zt2{*padding-right:6px;}

.mode_message .write_back .cont .zt textarea{width:100%;height:40px;padding:0 2px;

border:1px solid #D1E1EC;line-height:20px;color:#4F4F4F;}

.mode_message .write_back .cont .zt .normal textarea{height:23px;color:#B1B4B8;}

.mode_message .write_back .cont .zt .normal .op{display:none;}

.mode_message .write_back .cont .op{margin:5px 0 0;}

.mode_message .write_back .cont .op .bt_v2{padding:0 2px;vertical-align:middle;}

.mode_message .write_back .cont .zt{width:98.5%;*width:99.9%}

.mode_message:nth-last-child(1){border-bottom:none;}

/* E 訊息 基類 */

別忘了提示條,雖然是用於模組中,但它應該是可以被更廣泛使用的模組,因此我把它單獨提了出來:

CODE:

/* S 提示條 基類 */

.mode_hint{position:relative;margin:3px 0;padding:5px;

background-color:#FFFEAB;color:#000000;_zoom:1;}

.mode_hint .op{position:absolute;right:8px;top:5px;}

.mode_hint .op a{color:#000000;}

/* E 提示條 基類 */

還有像按鈕、全域性定義這些內容,就不列出了。完整的可以看:基類、擴充套件類例項 。例子中可以看到,擴充套件類的定義很少,只是一些簡單的定義,像B模組:

 CODE:

/* S 訊息 擴充套件 */

.message_nopic{padding-left:0;}

/* E 訊息 擴充套件 */

只需要一句,將頭像去掉即可。

6.6 CSS模組的註釋——頁面重構中的模組化設計(六)

從前面的內容我們已經知道,樣式是可以分成各個模組去寫的,如何表示各個模組的作用及它們之間的關係呢?CSS的註釋是不二的選擇。

與普通的註釋不同,模組的註釋需要一些更詳細的內容,比如:功能說明、模組版本、關聯資訊等等。 像《基類、擴充套件類──頁面重構中的模組化設計(五)》中例子的註釋,顯然是比較簡單的。為了減少不必要的溝通,我們可以使用較為固定的格式去完成這個註釋。

舉個例子:

 CODE:

/**

  * @name:mode_name

  * @author:ghostzhang

  * @version:1.0

  * @type:基類

  * @explain:Demo

  */

.mode_name{...}

.mode_name h2{

    ...

}

.mode_name .cont{

    ...

}

/* @end **/

/**

  * @name:mode_name_b

  * @author:ghostzhang

  * @version:1.0

  * @type:擴充套件類

  * @explain:Demo

  * @dependent:mode_name

  */

.mode_name_b{...}

.mode_name_b h2{

    ...

}

.mode_name_b .cont{

    ...

}

/* @end **/

從註釋中就可以知道mode_name_bmode_name_a之間的關係。

主要的關鍵字有:

@name

標明模組的名稱

@author

標明模組的作者

@version

標明該模組的版本

@explain

功能說明

@relating

標明該關聯的模組

@dependent

標明該所依賴的模組

@type標明該模組的型別:公共、基類、擴充套件類

需要注意的規則:

“/**”標記模組的開始

“/**”到第一個“*/”作為模組相關資訊的說明,包含關鍵字

關鍵字以[email protected]==開頭,“:”後開始到“*”的內容為相關的值,即:

@關鍵字:*

“/* @end **/”標記模組的結束

模組註釋內不可巢狀

提供了一個小工具(cssModeCODE: )幫助大家填寫樣式模組的註釋。