| 文章簡介:點分離(SoC)。他已經讓我們接受膨脹、報廢、冗餘、緩衝甚至更多。現在,我確信唯一的方法是遠離這一原則來改善我們的作者樣式表。 |
當談到CSS,我相信神聖的原則——點分離(SoC)。他已經讓我們接受膨脹、報廢、冗餘、緩衝甚至更多。現在,我確信唯一的方法是遠離這一原則來改善我們的作者樣式表。
對於從未聽說過SoC原則在Web設計中的上下文,它涉及到一些俗稱“三層分離”:
為了避免一些擔憂,將它劃分成獨立的資源:一個HTML文檔,一個或多個樣式檔案和一個或多個JavaSctript檔案。
但當涉及到表現層,“最佳實務”已經超出了資源的分離。CSS作者完全可能通過樣式表應付,例如Dave Shea寫的CSS禪意花園就是一個優秀的項目。CSS禪意花園是大多數(如果不是全部)開發人員用來做為如何寫樣式表的參考標準。
標準
今天能過實踐來幫我說明相關問題,我將使用一個非常常見的模組:媒體對象。它結合了HTML標記和CSS樣式,將是我們開始探討的起點。
模板結構
在我們的模板中,有一個容器(div.media)包含了一個連結容器(a.img),接著有一個div容器(div.bd):
<divclass="media"><ahref="http://twitter.com/thierrykoblentz"class="img"><imgsrc="thierry.jpg"alt="me"width="40" /></a><divclass="bd"> @thierrykoblentz 14 minutes ago </div></div>
CSS
我們給容器設定10px的margin,同時給容器和div.bd設定為一個BFC。換句話說,容器包含了一個浮動的連結,並且div.bd不能圍繞在連結的周圍。同時在圖片和文本之間設定一個10像素的margin(在浮動的一側):
.media{ margin:10px;}.media, .bd{ overflow: hidden;_overflow: visible;zoom:1;}.media.img{ float: left;margin-right:10px;}.media.imgimg{ display: block;}
結果
這是一個容器的表現形式,有一個圖片在連結中以及文本圍繞在一側:
新的需求出現時
假設我們現在需要將文本顯示在映像的另一邊。
模板結構
非常慶幸BFC的魔力,現在我們需要修改連結的樣式風格。為此,我們給圖片增加一個新的類名imgExt。
<divclass="media"><ahref="http://twitter.com/thierrykoblentz"class="imgExt"><imgsrc="thierry.jpg"alt="me"width="40" /></a><divclass="bd"> @thierrykoblentz 14 minutes ago </div></div>
CSS
我們將添加一個向右浮動的樣式給連結,並修改他們的margin值:
.media{ margin:10px;}.media, .bd{ overflow: hidden;_overflow: visible;zoom:1;}.media.img{ float: left;margin-right:10px;}.media.imgimg{ display: block;}.media.imgExt{ float: right;margin-left:10px;}
結果
映像現在顯示在另一邊:
另一個需求出現時
假設我們現在需要在正常的頁面中將文本設定的更小。為此,我們建立一個新規則,使用#rightRail作為內容相關的選取器:
模板結構
我們的模組現在放在一個div#rightRail的容器裡面:
<divid="rightRail"><divclass="media"><ahref="http://twitter.com/thierrykoblentz"class="img"><imgsrc="thierry.jpg"alt="me"width="40" /></a><divclass="bd"> @thierrykoblentz 14 minutes ago </div></div></div>
CSS
再一次,我們建立一個額外的規則,這一次使用後代選取器#rightRail .bd:
.media{ margin:10px;}.media, .bd{ overflow: hidden;_overflow: visible;zoom:1;}.media.img{ float: left;margin-right:10px;}.media.imgimg{ display: block;}.media.imgExt{ float: right;margin-left:10px;}#rightRail.bd{ font-size: smaller;}
結果
這裡是我們的原始模組,顯示在div#rightRail內:
這個模組有什麼錯誤?
- 在樣式表中給模組改變簡單的樣式可以得到新的效果:必須有一個方法不總是為需要的樣式風格寫更多的CSS規則。
- 組合選取器是常見的樣式(
.media,.bd{}):使用了組合選取器,而沒有使用一個類定義樣同的樣式,而導致更多的CSS。
- 我們有六種規則,四種規則是基於上下文:上下文相關的規則是很難維護的。樣式與這些規則不太可重用。
- RTL和LTR介面變得複雜:改變方向,我們需要覆蓋我們的一些樣式(即寫更多的規則)。例如:
.rtl.media.img{ margin-right: auto;/* reset */float: right;margin-left:10px;}.rtl.media.imgExt{ margin-left: auto;/* reset */float: left;margin-right:10px;}
滿足原子層疊樣式表
a·tom·ic:組件中的單元組成一個更大的系統。
我們都知道,越小的單位,更可重用它。
把代碼當作成樂高。把代碼盡可可能斷成小塊的。——@csswizardry(via@stubbornella)#btconf
將樣式分解成單元塊,我們可以將這些單元區塊對應到樣式中的單個類,而不是很多。這個規則將導致一個更細粒度的規則,進而提高可重用性。
讓我們重新考慮媒體對像使用這種新方法。
模板結構
我們使用了五個類名,沒有哪個類是與內容相關的:
<divclass="Bfc M-10"><ahref="http://twitter.com/thierrykoblentz"class="Fl-start Mend-10"><imgsrc="thierry.jpg"alt="me"width="40" /></a><divclass="Bfc Fz-s"> @thierrykoblentz 14 minutes ago </div></div>
CSS
每個類都關聯到一個指定的樣式。在大多數情況下,這意味著我們有一個聲明規則。
.Bfc{ overflow: hidden;zoom:1;}.M-10{ margin:10px;}.Fl-start{ float: left;}.Mend-10{ margin-right:10px;}.Fz-s{ font-size: smaller;}
結果
這個如何?
現在我們忽略了類名和關注是這樣做(或不這樣做)。
- 沒有上下文樣式:我們沒用使用上下誩或後台選取器,這意味著我們的樣式沒有權重一說。
- 方向(左和右)是“抽象的”:不用覆蓋樣式,容器在樣式表中使用了RTL規則,例如下面的代碼:
.Fl-start{ float: right;}.Mend-10{ margin-left:10px;}
相同類名,相同的屬性,不同的屬性值。
但要注意最重要的事情是,我們美化模板樣式。我們已經必變了模上下文樣式。現在編輯HTML模板而不是樣式表。
我相信這種方法是改變了,因為它大大縮小了範圍。我們樣式不是全域的,只是模組的和塊層級的樣式。我們可以改變一個模組的樣式,而不用擔心破壞別的頁面。我們可以不做什麼給這個樣式表添加任何規則,只需要建立一個新類名和規則:
.someBasicStyleForThisElementHere {...}
這樣一來沒有冗餘。選取器是不重複的,樣式是屬於一個單獨的而不是其他的一部分。例如,在樣式表中頁麵包含了72個float的聲明。
同時,放棄一種樣式——例如,總是保持圖片在左側的模組——這並不會任何樣式規則過時。
聽起來不錯吧?
不是吹的吧?我聽到了你說“這就違背了書中每一個規則”。這沒有與行內樣式比。你的類名是神秘的,但也是不具語義化的。
這是公平的。讓我們解決這些問題。
關於沒有語義化的類名
如果你查閱了W3C的網站管理的技巧,它說“好名字不改變”,你將看到這樣的論點是關於維護,而不是語義化本身。所也這樣說的也是,在CSS檔案中修改樣式要比在多個HTML檔案中修改要來得容易多。如果只改變一個元素的樣式而要求我們修改聲明,.border4px將是一個不好的類名,這類名和名字聯絡在一起。換句話說:
.border4px{border-width:2px;}
關於語義模糊的類名
在大多數情況下,這些類名名稱遵循Zen Coding的文法——查看Zen Coding字元表(PDF)——現在稱為Emmet。換句話說,他們是簡單的縮寫。
關於(left和right)相關聯的樣式,包括一個組合聲明。例如,Bfc代表“塊格式化上下文”。
關於模仿行內樣式
希望下圖能協助你清理:
- 特殊性(Specificity):這項技術並不像
@style具有特殊性。他的樣式權重很低,因為都只是依賴於單個類名,而不像.parent .bd{}這樣的後代選取器,選擇為0.0.2.0(有關於權重的相關教程,請查閱CSS Specificity: Things You Should Know)。【中文版本可以點擊《你應該知道的一些事情——CSS權重》】。
- 冗餘(Verbosity):大多數類是採用縮寫來聲明樣式(例如,
M-10表示的是margin:10px)。一些類名,如.Bfc是指多於一種樣式的集合(如上圖的映射部分)。還有其他一些類使用start和end這樣在關鍵詞,而沒使用left和right值(見上圖中的抽象部分)。
下面是@style的一些優點:
- 範圍(Scope):樣式就是將接點相連在一起的一個“沙箱”。
- 可移植性(Portability):因為樣式是封裝在一些的,你可以移動到模組中而不會丟失他們的樣式。當然,我們仍然需要樣式表;但是,因為不受限於上下文結構,模組可以放置在任何一個頁面上,網站中甚至是網路中。
臃腫的路徑
因為模組的樣式是直接依靠類名,他們可以實現我們想要的任何效果。例如,如果我們需要建立一個簡單的兩列布局,我們所需要做的是在模板中用div來替代當初的連結。看起來像這樣:
<divclass="Bfc M-10"><divclass="Fl-start Mend-10 W-25"> column 1 </div><divclass="Bfc"> column 2 </div></div>
我們只需要在樣式表中增加一個額外的規則:
.Bfc{ overflow: hidden;zoom:1;}.M-10{ margin:10px;}.Fl-start{ float: left;}.Mend-10{ margin-right:10px;}.Fz-s{ font-size: smaller;}.W-50{ width:50%;}
與傳統方法相比:
<divclass="wrapper"><divclass="sidebar"> column 1 </div><divclass="content"> sidebar </div></div>
這裡我們需要建立三個新的類名,添加一個額外的樣式規則和組選取器:
.wrapper, .content, .media, .bd{ overflow: hidden;_overflow: visible;zoom:1;}.sidebar{ width:50%;}.sidebar, .media.img{ float: left;margin-right:10px;}.media.imgimg{ display: block;}
我認為上面的代碼很好的展示了SoC原則。根據我的經驗,它只是增加了樣式表大小。
此外,檔案越大,越有由複雜的規則和選取器組成。然後沒有人敢去編輯現有的樣式規則:
- 我們不敢去修改樣式規則,害怕修改現有樣式規則後會破壞一些東西。
- 我們只能建立新的樣式規則,而不是修改現有樣式規則,因為我們不確定後者是100%安全的。
換句話來說,我們使事情變得更糟糕,因為我們使檔案變得越來越臃腫。
如今,人們習慣於非常大的樣式表,和很多程式員認為他們熟悉他們的領域。而不是去思考減少臃腫,他們使用工具(如前置處理器)來協助他們去處理它。Chris Eppstein告訴我們:
LinkedIn有超過1100個Sass檔案(每個SCSS檔案有230K行)和每天有超過90個開發人員在編寫Sass。
CSS臃腫對比HTML臃腫
讓我們一起來面對它們:資料必須放對地方。考慮下面的兩種結構
<divclass="sidebar"><divclass="Fl-start Mend-10 W-25">
在很多案例中,語義化的類名要比表像的類名使用更多的位元組(.wrapper與.Bfc對比)。但我不認為這是一個真正讓人擔憂的問題,相比之下,現在大多數應用都在使用data-屬性。
這就是gzip進來的好處,因為高冗餘的類名在整個文檔將取得更好的壓縮。同樣的道理也適用於樣式表中,我們有很多冗餘的樣式:
.M-1{margin:1px;}.M-2{margin:2px;}.M-4{margin:4px;}.M-6{margin:6px;}.M-8{margin:8px;}etc.
緩衝
表面上的規則不改變。樣式表由這些成熟的工具集製作,作者可以找到他們所需要的一切。通過他們的特徵,他們停止增大檔案,成為不可變的。而不可變是緩衝最友好的。
沒有更好的.button類名?
這裡討論的技術並不是禁止語義化類名和規則,以及群組選取器聲明樣式。這個想法只是為了評估常用的方法的好處,而不是採用它作為事實上的技術來美化Web頁面。換句話說,我們是限制“組件”方法的幾個案例,這是很有意義的。
例如,你可能會發現我們的樣式表中有以下規則。這些規則設定我們的樣式,我們不建立簡單的類或規則,確保跨瀏覽支援。
.button{ display: inline-block;*display: inline;zoom:1;font-size: bold 16px/2em Arial;height:2em;box-shadow: inset 1px 1px 2px 0px #fff;background: -webkit-gradient(linear, left top, left bottom, color-stop(0.05, #ededed), color-stop(1, #dfdfdf));background: linear-gradient(center top, #ededed 5%, #dfdfdf 100%);filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#ededed", endColorstr="#dfdfdf");background-color:#ededed;color:#777;text-decoration: none;text-align: center;text-shadow:1px 1px 2px #ffffff;border-radius:4px;border:2px solid #dcdcdc;}.modal{ position: fixed;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%);*width:600px;*margin-left: -300px;*top:50px;}@media \0screen { .modal{ width:600px;margin-left: -300px;top:50px;} }
另一方面,你將在樣式中看到如下所列的規則(即樣式綁定到特定的模組),因為我喜歡將相同的風格使用多個類來實現:一個用於字型大小、顏色,一個用於浮動等。
.news-module{ font-size:14px;color:#555;float: left;width:50%;padding:10px;margin-right:10px;}.testimonial{ font-size:16px;font-style: italic;color:#222;padding:10px;}
我們包括所有可能的風格在我們的樣式表?
這個想法是為了擁有一個規則,作者可以選擇他們想要的任何樣式。跨網站的樣式風格是常見的,足以讓這些成為樣式表中的一部分樣式。如果一個風格太具體,那麼我們就會依賴於@style(樣式屬性)。換句話說,我們寧願修改標記而不是樣式表。主要目的是建立一個規則表,解決各種設計模式。比如一個元素的float的基本規則可以添加一個helper類名來完成。
/** * one liner with ellipsis * 1. we inherit hyphens:auto from body, which would break "Ell" in table cells */.Ell{ max-width:100%;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;-webkit-hyphens: none;/* 1 */-ms-hyphens: none;-o-hyphens: none;hyphens: none;}/** * kinda line-clamp * two lines according to default font-size and line-height */.LineClamp{ display: -webkit-box;-webkit-line-clamp:2;-webkit-box-orient: vertical;font-size:13px;line-height:1.25;max-height:32px;_height:32px;overflow: hidden;}/** * reveals an hidden element on :hover or :focus * visibility can be forced by applying the class "RevealNested-on" * IE8+ */:root.NestedHidden{ opacity:0;}:root.NestedHidden:focus, :root.RevealNested:hover.NestedHidden, :root.RevealNested-on.NestedHidden{ opacity:1;}
這種規模如何?
我們剛剛發布了一個全新的My Yahoo,在很大程度上依賴於這種技術。這是它與雅虎其他產品的對比(gzip壓縮後):
我們樣式表大約是17.9kb大小(約3kb是可調整的),它是可共用的(與樣式表的其他屬性)。原因是,沒有任何規則包含了內容。
結束
因為表像的類名一直被視為“界外”,我們、社區沒有真正調查他們的使用需要。事實上,在這個名字的最佳實務,我們已經駁回了每一個機會去發掘自己潛在的好處。
在雅虎,@renatoiwa,@StevenRCarlson和我正在開發的項目使用了這個新的CSS架構。【中文版本,可以點擊這裡閱讀】。代碼似乎是可預測、可重用、可維護和可擴充的。到目前為止,這些都是我們所經曆的結果:
- 少臃腫:我們可以不添加一行樣式到樣式表中建立整個模組。
- 快速開發:樣式由與內容無關的類控制,因此我們可以複製和粘貼現有模組。
- 自由的RTL介面:使用
start和end關鍵詞有很大意義。它為我們省去了為上下文RTL編寫額外的樣式規則。
- 好的緩衝:大量的CSS可以跨產品和屬性共用。
- 非常小的維護(CSS方面):只有一套小樣式規則在隨著時間變化。
- 抽象少:沒有必要在一個樣式表中找出一個模板的樣式規則。這是所有的標記。
- 第三方開發:第三方可以把我們一個模板無需附加樣式表(或樣式塊)應用到項目中。沒有自訂規則,意味著第三方沒有打破規則,沒有恰當的名稱空間。
注意,如果維護而言,維護CSS方面總比維護HTML方面容易,那麼很簡單,我們可以在CSS方面不做樣式清理。但如果我們必須保持簡潔,那麼我們同樣面對一些痛苦的事情。
最後注意
在幾個星期前,我在一次聚會中聽到Colt McAnlis說“工具,而不是規則”,快速搜尋這個詞返回這個:
我們都需要接受新知識、新方法、新的最佳實務,我們需要能夠分享他們。
譯者手語:整個翻譯依照原文線路進行,並在翻譯過程略加了個人對技術的理解。如果翻譯有不對之處,還煩請同行朋友指點。謝謝!
如需轉載,煩請註明出處:
英文原文:http://coding.smashingmagazine.com/2013/10/21/challenging-css-best-practices-atomic-approach/
中文譯文:htpp://www.w3cplus.com/css/challenging-css-best-practices-atomic-approach.html