1. 程式人生 > >CSS 中的分離、抽象和層疊

CSS 中的分離、抽象和層疊

CSS 中的分離、抽象和層疊
摘要:LESS和Sass(或者類似方案)從三個方面解決了css存在的問題:分離,抽象和層疊。當我在接受他們時,我發現css還有一些其他問題需要解決。在這裡我提出些解決方案。

介紹

有很多充分的理由說明LESS和Sass的用途。css很難做到可維護性。LESS和Sass(類似工具)使css變成了一個更加易用的語言。

但是,當人們談論到為什麼他們如此強大時,往往都失去了主見。的確,你的樣式檔案更簡潔和易讀了,然而,這裡還有比純粹的節省程式碼量和命名更深層次的東西。

在這篇文章中,我將從一個開發者和程式語言愛好者的直覺感受到的,儘可能圖文並茂的解釋下為什麼css天生難以維護,並且沒有達到他自身的設計目的;為什麼LESS和Sass使這個糟糕的語言變得更加可用。我也將提出具體的解決方案,這些將使LESS和Sass提高到更高的一個層次。

零度分離

在以前,人們用HTML tables來設計頁面的樣式,檔案看起來像醬紫:

CSS出現時,人們討論了很多關於頁面內容和樣式的分離的問題。CSS基本上幫助你把樣式從HTML檔案中脫離出來。

樣式仍然與你的樣式檔案定義的樣式結構相關。他們沒有自己的分組,如果你想重複利用一段樣式,那麼你可以複製貼上,或者通過逗號分隔方式公用一段樣式。但是兩種方式都很糟糕!

還有一種更糟糕的解決方式,也是最常見的一種方式,那就是按照命名給定樣式,我們可以看到在很多號稱讓你的html中寫更少樣式資訊的糟糕的“css框架”中,應用的非常多。網格系統(grid)就是個很典型的例子。

但是這些問題出現的原因,不在於這些css框架的作者,很多web開發者也都在尋求解決這些問題的方案。歸根到底,這些都是css作者的責任。使用css,的確能做到頁面內容和樣式分離,但是實現起來很費勁。

HTML和CSS的獨立性是不一樣的。HTML可以沒有CSS,但是CSS沒有了HTML,狗屁不是!

 

如果你真的想實現頁面內容從樣式分離,你必須把html和css放在同等的基礎上設定,像這樣(譯註:圖裂了):

頁面內容放到html檔案,樣式寫到css檔案中,然後通過第三種語言建立他們之間的關係。

LESS的 LESS Elements讓其成為可能。人們在討論LESS時,往往關注的是它減少了樣式的定義和重複性,或者隱藏了依賴於瀏覽器的css特性。但是,這些都不是問題的本質。之前所有的討論都試圖實現通過定義一個獨立於HTML檔案的mixin樣式,然後只需根據定義的名稱繫結到一個或者多個HTML元素。

使用LESS,我可以定義個混合類Dorothy:

.dorothy() { background-color: green; text-color: yellow; border: 1px solid red;}呵呵,這個樣式看起來有點醜,但是它僅是個樣式。它不依賴於任何的HTML結構,甚至一個HTML標籤。現在,如果你想使用它,只需要在需要的地方引用它就可以,下面是幾個例子。 div.main { .dorothy;}blockquote { .dorothy;}

這是LESS讓HTML樣式更加易用的一個方面,除此之外,你可以定義個包含大小和顏色的變數,這也是把樣式繫結到HTML的另外一種方式.

抽象

如果你對混合類和變數有了進一步的認識,你會發現他們可以任意組合。我可以定義一個混合類,然後在另一個混合類裡面引用它。我也可以用他們組合出第三種樣式,紅色邊框,黃色字型,綠色背景。這類的組合表明我們可以對css做進一步的抽象。

這在單純的HTML+CSS裡面是不可能辦到的。

好吧,雖然我說了不可能辦到,但是也不是沒有辦法,只是有點2x罷了。諾,你可以複製貼上嘛,這TM雖然根本不是個解決方案,但是也能得到你想要的樣式。或者你可以像網格框架(blech!)一樣重複使用沒有語義的類名。最後,你可以做個“倒置樣式”(inverted-style):把所有樣式的優先順序看做最高,其他的選擇器都是從屬。這個需要解釋下。

 

通常,我們這樣寫css:

div.main { background-color: green; text-color: yellow; border: 1px solid red; margin-top: 10px;}blockquote { background-color: green; text-color: yellow; border: 1px solid red;}p { margin-top: 10px;}

這樣看起來似乎不是很糟,但是仍存在一些重複的定義。我們可以採用另一種方式。

/* Dorothy style */div.main, blockquote { background-color: green; text-color: yellow; border: 1px solid red;}/* Top margin */div.main, p { margin-top: 10px;}


如果我們需要給div.footer定義個上邊距,我們只需要把他新增到選擇器裡面就行,不用重新定一個規則了。我確信別人已經想到了這種風格的寫法(或許起了個更好的名字),但是我不知道。我想這也是css作者的初衷之一吧。在實際中,以我的經驗來看,這樣的方式很難做到。不知為何,我沒有這樣的習慣去保持樣式從他們的規則中獨立出來。css屬性和div.main,blockquote相關聯,但是不符合dorothy(一種樣式風格)第一條原則。也許專業人士能做的更好,但我從來沒遇見過。

使用LESS就沒這些問題。我只需要定義一個混合類,然後在我需要的地方複用它就可以了。

層疊

對於層疊問題LESS和SASS提出了一種很好的解決方案,但是有一定的侷限性。層疊是複雜性中最基本的一個問題。對於一個特定元素的特定的屬性,有很多地方的值是需要設定的。然而確定這些所有地方的優先權的規則是很複雜的。

一個元素的最終CSS屬性值是由以下因素決定的:

  • 匯入CSS的順序
  • CSS規則中定義的class的數量
  • 在檔案中定義的規則的順序
  • 所有的繼承的屬性設定
  • 元素的 tag name
  • 元素的 class
  • 元素的 id
  • HTML樹中所有元素的祖先元素
  • 瀏覽器的預設樣式

確實,css樣式屬性被很多影響著,但,智者總會讓所有事情保持乾淨和簡單。其實,保持這種智慧行為僅僅在小專案中有效,但在其他一些時候,層疊樣式將會傷害到你。

Jason Zimdars 在37 Signals展現了他們提出的層疊樣式的解決方案,他分享了一些關於層疊問題的分析和LESS怎麼能消除層疊問題的觀點。

如果css的層疊可以受控制,我們將第一次能夠明確自己寫的css不會引起問題,這將促使我們創造帶有自身包含的樣式表的元素,這些元素放之四海皆有效!

內容和樣式的分離聽起來像聖盃一樣響亮!

通過使用巢狀的LESS規則和子選擇器,我們能夠避免大多數的層疊帶來的痛。聯合其他的一些技巧,我們能夠將我們的樣式混合到一塊(或者是混合中巢狀混合),並將這些樣式和通過模仿html結構的巢狀規則繫結到一塊。

這是完美的,最終的解決方案嗎?不一定!

將來

也有其他一些嘗試解決層疊問題的方法,LESS和Sass被用來作為css的父集,這就意味著你可用的css檔案就自動的成為LESS檔案,同時也意味著你一開始就得用LESS編譯器。

在這種情況下,LESS將會同事擁有所有css沒有解決的問題,我建議在下一步可以嘗試採用css子集並加以實踐,同時,也非常希望聽到大家的意見!

是的,巢狀規則確實可以處理層疊問題,但是也有其他關於層疊的問題。樣式的混合不能真的幫你解決盒模型,再多的變數和演算法也不能讓兩個DIV的寬度相同。

接下來,我將一個一個的解決這些問題。

再次“層疊”

直率的說,層疊就是css的創作者犯的一個錯誤,層疊的運用一開始希望是美好的,但在實際的運用中表現的並不理想。

事後諸葛亮,各個瀏覽器統一的層疊樣式真的是我們所需要的,CSS reset真的是一項漂亮的發明,它精彩的解決了不同瀏覽器之間的預設樣式的不同,它可以讓你不用考慮預設樣式輕鬆的開始頁面的製作,所以,css reset可以實現頁面樣式預設,但除此之外,它中間的一些樣式可能不能被充分的利用。

有的時候,你可能會想用層疊,例如,你想要設定整個文件的字型,所以, 你設定 body{ font-family:'Comic Sans';},0K,間接的利用font-famiy屬性的繼承性便將整個文件的字型搞定了。事實上,如果你想每個標籤都有同樣的屬性,可以這樣寫:* {font-family:'Comic Sans';},其實這和css reset 有異曲同工之妙,都是為樣式設定預設樣式 。

這意味著一條原則:一次性地重置一些預設樣式並避免使用樣式重疊。接下來我們需要能系統地遵循此原則。這是新的程式碼結構的樣子:

不使用樣式重疊意味著我們必須嚴格要求自己不在同一頁面元素上應用多個樣式規則。我無法告訴你要怎麼做才能嚴格達到此要求,但是有些準則是可以參考的。

  1. 重置預設樣式的規則只使用bare (classless + non-nested) selectors。
  2. LESS規則中不要用bare selectors。
  3. LESS規則中不要有重複的選擇器。

這些準則會限制樣式重疊的出現次數,再結合使用Zimdars提出的解決方案,效果會更佳。

常見錯誤

我把他們叫做常見錯誤是因為找不到更好的詞來表達了,但實在是他們存在於CSS中。

盒子模式

盒子模式的引入可以使我們避免犯一些簡單錯誤。

其中一個錯誤是發生在你定義左間距而不是右間距的時候。在這種情況下,右間距該怎麼定義呢?級聯。

當我設定寬度為100%的時候會出現什麼情況?如果有級聯填充的話。哎呦,媽呀,怎麼辦?當複合屬性存在的時候不要單個的使用CSS屬性。

個人建議不要採用以下屬性:

  • left-margin,right-margin,top-margin,bottom-margin; usemargininstead
  • left-border,right-border,top-border,bottom-border; useborderinstead
  • left-padding,right-padding,top-padding,bottom-padding; usepaddinginstead
  • width,height; use the .dimension mixin instead

為了得多更多的規則,混合界定如下:

.dimension(@w,@h) { width : @w; height : @h; margin : 0; padding : 0; border-width: 0;}

這就需要你一開始就設定高度和寬度,它會重新設定內邊距,外邊距和邊框,由於有盒子模式,這些都會影響真實的寬度。然而你還是可以無視他們,你只需要明確化。雖然這個不能解決整個盒子模式問題,但是能減去很多意外的行為。

我推薦使用混合是因為不管什麼時候你設定一個元素的尺寸,由於他們影響盒子模式,在這一點上你應該明確內邊距,外邊距和邊框。

字型顏色

現在我就挑一些反面案例

你見過下面這些程式碼多少次了?

body { color: black; a:link {color: blue; } a:hover {color: red; } a:active {color: blue; } a:visited {color: purple; }}實在太多了。我經常忘記一些。是時候改成混入處理了。 .font-color(@f,@a:blue,@h:red,@c:blue,@v:purple) { color: @f; a:link {color: @a}; a:hover {color: @h}; a:active {color: @c}; a:visited {color: @v};}模式很清楚吧。

結論

CSS從未完全實現樣式與內容的分離。LESS(和Sass)終於能使這種分離實現。而且,使用LESS,我們可以開始磨圓CSS中尖銳的邊角部份。但是,我們應該去尋找CSS的一個子集並用mixins替換有問題的CSS屬性,而不是將LESS做為CSS的超集使用。該子集可以用一個linter工具強制執行。 這些建議是一個很好的開始,但仍有很長的路要走。

後記

最後我想提一個關於CSS層疊的反思,但在上文中沒有找到一個合適的地方,主要因為它不是一個問題而只是個不便。我經常疑惑為什麼在CSS中,元素樣式(定義在HTML標籤的樣式屬性中)的優先順序高於所有其他樣式。同樣,為什麼在HTML(style標籤)中定義的樣式優先於那些通過連線引入的外部樣式?我認為應該是完全相反的才更有意義。 HTML頁面可以為其元素定義預設樣式,這應該是在頁面中指定並用外部樣式表進行覆蓋。


然而,按實際的規則,如果想改變一個有元素樣式的元素的樣式我必須修改相應的HTML檔案。這不是與CSS的意圖完全相反嗎?