CSS語義思惟

前一陣子在項目組中講了一個關於CSS的Session,在講以前我曾收到了許多意見,大部分是但願能講講CSS實用性的技術,好比盒模型,CSS3之類的。乾貨人人都喜歡,由於看得見摸得着,拿來就有用,但我最後仍是決定講一些」溼貨「。由於在Code Diff的時候我發現了許多樣式的問題不是因爲不會寫CSS致使的,而是因爲在錯誤的地方使用了寫在錯誤地方的樣式。css

其實CSS很簡單,沒有計算沒有流程,只是一直描述,不管什麼複雜的效果,你只要Google一下就知道怎麼寫了,甚至能夠直接copy。但CSS又很複雜,一個元素的表現會受到它旁邊的兄弟元素,也會受到內部的子元素影響,還會受到父元素影響,在這種多重影響下,一個元素的顯示邏輯會變得錯綜複雜。有沒有面對塌陷的塊級元素而一籌莫展?不管怎麼改它的屬性就是得不到本身想要的,但看看彷佛如出一轍的示例程序卻安然無恙,是否是恨得咬牙切齒?我想這就是本文所要解決的主要問題,讓你學會如何優雅的寫CSS。html

涇渭分明 - 明確書寫意圖和表現語義

其實咱們只要稍微接觸過CSS,必定都學過盒模型,我假設你已經對margin、padding和border已經很熟悉。好了,咱們常常會遇到一種狀況,想讓父元素和子元素之間有一些空間,好比佈局的時候,container和content之間的留白。通常來講有兩種方式,一種是給父元素加padding內邊距,另外一種是給子元素加margin外邊距。如今想一想,你是否慎重考慮過用哪種方式?你是否明白二者的區別?若是你從未考慮過這些,如今考慮也不遲,這真的很重要,若是你真的想優雅的運用CSS,而不是被它耍的團團轉,若是你真的想把CSS寫出規模,那你就要認真的思考這裏面的邏輯。git

先說說父元素的container加上padding的方式,子元素的背景將不會延伸到空白區域,另外一種給子元素加margin的方式則反之。但我想先拋下這個表象,看看此時加上padding的父元素的邏輯。它意味着,我建立了一個容器,而且該容器的內部有一些區域是被看不見的東西填充的,不管放入什麼都不該該佔據這個區域。在你的腦海中想象一個厚厚的玻璃瓶,它就好像是在說「雖然我是透明的,可是在這厚厚的玻璃以內纔是你應該呆的地方,不管是什麼只要你想放在瓶子裏」。如今來看看子元素,是的,其背景也應該而且確實在內部,而不應占據那段空白的區域。若是是爲子元素加上margin,這意味着我在容器中建立了某個東西,而這個東西有一個本身的地盤,容器內的其餘東西都不能進入這裏。github

因此他們的本質區別在於其所表達的意義,也就是語義,一個是容器上的語義,另外一個是容器內元素的語義,主語也不一樣,謂語意義也不一樣。那麼這能說明什麼呢,不得不提一下高級語言中的高級,這表明某個語言將機器語言封裝的更好,接口更接近天然語言,其強大不言而喻。其實編程語言的發展軌跡就是不斷把機器語言往天然語言翻譯,讓人們能夠更容易的跟機器溝通,終極目標天然是人工智能,和機器用天然語言自由溝通。因此雖然代碼或者說CSS的語法並無什麼變化,但咱們應該在思惟上清楚的區分代碼片斷的意圖和語義來寫CSS。編程

語言學家喬姆斯基曾構造過一句符合語法的話:瀏覽器

「Colorless green ideas sleep furiously」框架

意思是無色的綠色想法憤怒的睡覺。想法睡覺是違反常識的,無色的綠色是矛盾的,憤怒的睡覺是不合常理的。僅僅符合語法是不夠的,僅僅不報錯也是不夠的,尤爲是CSS這種描述性的語言不多會報錯,因此我想說的是,其描述性質讓咱們有更多選擇來實現咱們所指望的效果,但咱們卻應該慎重,要讓語義分明,而不是在有限的語法規則下任意妄爲,那樣寫不出好的CSS代碼。除了其自己的語法規則,咱們必須自我約束,引入語義規則,不只僅是爲了提升可讀性這樣的理由,而是拉近人與機器的距離,讓咱們在思惟上更加和代碼契合,這樣才能寫出優秀的程序。less

言歸正傳,究竟如何語義化CSS呢。以前有講過OOCSS,其實面向對象的思想就是一種語義化,將虛擬的元素看做實際的對象,用常識來構造代碼,就像是用戶體驗中的用戶習慣同樣,這是一種遍佈全人類的用戶習慣,讓代碼更友好,即所謂的優雅。編程語言

好比最多見的佈局,咱們通常都會有header、body和footer,這樣無需任何說明和規則,誰都會理解,header在前,footer在後,中間是body。有趣的是table中的thead、tbody和tfoot,因爲加載優化,咱們即便把tfoot放在tbody前面,讓其先加載,但顯示的時候tfoot仍然會在tbody下面,因而可知語義化的重要,不然你必定會覺得不是W3C的人弄錯了標準,就是瀏覽器廠商搞出了Bug。雖然這是HTML標籤不是CSS,但我以爲這個例子很恰當的說明了一點,顯示邏輯是獨立的,不該該和其餘邏輯混爲一談,它應該只關心如何顯示。ide

再好比,一個導航條通常分爲左右兩邊,裏面各有若干連接。你會如何命名?navbar-left和navbar-right是Bootstrap所使用的class,但當寬度減小,Responsive響應式的Bootstrap會讓這些連接都收進下拉菜單中,左和右又從何談起呢?一樣是Bootstrap中的顏色命名就作的十分紅熟,不是green、blue、red這些詞彙,而是success、primary、warning這些詞,它們的區別是表現化與語義化的區別,我喜歡把這個叫作顯示邏輯。也就是說在class層面咱們應該只關注元素(或者說對象)是用來作什麼的(意圖)以及它應該表示什麼(語義)。這裏三種顏色表明成功、重要和警告,至於咱們是用綠、藍和紅來表示仍是經過其餘什麼顏色甚至形狀,應該在style層面寫CSS屬性表示。如此咱們使用class時無需迷茫於表示成功應該用綠色仍是紅色,意圖明確無誤。回到導航欄的例子,咱們應該使用main和sub之類的詞語標識導航欄中重要的和次要的連接,即便在某些實現下,主要和次要沒有區別也不用擔憂,那是該實現的顯示邏輯,咱們不該該橫加干涉。

狡兔三窟 - 善用class與style多對多的複雜關係

說到class和style(樣式屬性),這又是一段混亂不清的關係。其實每當咱們要實現一個樣式,自覺或不自覺的都會考慮,是將元素和class一一對應,而後爲元素上的class寫style,仍是用class和幾條style對應以後在元素上搭配組合。前者的好處是每一個class中的style不會影響其餘class,但可用性十分的低,極端點說這已經不算是在編程了,而是在畫頁面;後者的好處能夠靈活使用不一樣的樣式搭配給元素使用,組合出元素須要的效果,但很難維護,牽一髮動全身,樣式很難測試,沒法保證在你動了一條style以後,沒有影響其餘的地方。甚至最要命的是大部分CSS代碼都是無心識的遊走在這兩種狀況之間,因此咱們要作的不是選擇一種極端,而是找到一個平衡點,並使用一些方法使得咱們的CSS既能靈活複用在各類元素上,又能易於維護,不致修了這破壞那的狀況。

分組

首先,對於一個或一套元素的樣式,咱們應該有本身的建立原則,而不是想到哪寫到哪。好比,我通常使用這樣的步驟來建立元素:

1. 結構

首先僅關注結構佈局,以站點總體爲基準,將元素抽象爲一個或多個結構。

好比製做一個按鈕,你也許會發現它的尺寸和導航上的連接一致,而內外邊距以及display和overflow之類的屬性又和頁面容器同樣,這時你就能夠把按鈕的結構拆成兩個結構,一個是尺寸,一個是邊界邏輯,這種狀況時常發生,因此有的CSS理論認爲應該把width和height這對尺寸屬性和padding以及margin這對邊距屬性完全的分開也是這個道理。其實並非說它們4個放一塊兒就決定不行,只是通常它們都有各自複用的價值,因此經常被拆開使用,歸根揭底這是由顯示邏輯決定的。

2. 皮膚

通常因爲設計統一性,咱們能夠藉助設計指導,輕鬆的製做出標準皮膚。但要注意的是,皮膚指的不只僅甚至不必定是顏色之類的。繼續用Bootstrap舉例,有5種基礎顏色,但這並非皮膚,5種顏色的語義不一樣,它們只是默認用了5種顏色,勉強能夠看做默認皮膚,而真正的皮膚是theme,讓按鈕變得有立體感。還有一個誤區就是認爲哪幾種屬性是皮膚,哪幾種不是。就像前面所說的,咱們要在語義上進行劃分。一個屬性在某些意圖下多是結構,在另外的意圖中多是皮膚。

Logo

舉個極端的例子,在一個Workshop中我用CSS和HTML製做了左邊這樣的Logo,Logo自己應該徹底算是皮膚,由於通常來講就是一張圖片,因此製做它的全部CSS屬性都應該算做皮膚。下面的CSS代碼中,不管是定位仍是文字的處理,以及尺寸等,都是爲了構造Logo,因此這些屬性都是皮膚。

css#logo i, #logo b {
  position: relative;
}
#logo i {
  left: -30px;
  transform: rotate(-30deg);
  font-size: 60px;
  letter-spacing: -11px;
  opacity: 0.3;
}
#logo b {
  top: -43px;
  left: 40px;
  font-size: 68px;
  word-break: break-all;
  width: 3px;
  line-height: 10px;
  text-indent: 6px;
}

3. 狀態

除告終構和皮膚,其實還有一類很容易被人忽視的樣式,即便是設計人員也常常忘了它,那就是狀態。最多見的是hover,鼠標觸碰元素與否的狀態,以及active,當前選中的標籤,當前所在的分頁等等。一般人們會把它劃分到皮膚中,但你要明白咱們劃分的依據是意圖,很顯然,狀態不是皮膚,僅僅是一般爲表達某些狀態時會使用一些顏色,畢竟顏色是最好的表示方法。它還與各類邏輯有着千絲萬縷的聯繫,常常會使用JavaScript來加以控制,因此將狀態單獨分出來是極有必要的,JavaScript只須要更改一個class就能夠實現狀態的切換,而不是在執行的時候纔想起來應該把哪裏隱藏把哪裏顯示,或者是變個顏色出個動畫之類的。

使用

接着,不管咱們是已經把各類寫好的CSS屬性分好了組,仍是正準備以這種方式開始寫CSS,我先引入一個語言學的術語 語塊(Lexical chunk),創造這一術語的 Michael Lewis 認爲語言並不是由傳統語法和詞彙組成,而是由多個詞彙的預製語塊組成。咱們如今分好的組其實就是一個個CSS的語塊,CSS自己就是這種預製功能,咱們要作的就是把style語塊化,而後在HTML中寫上表明它的class名稱,當HTML元素上的多個class組合在一塊兒時就組成完整的語義。

好比表示步驟的元素,這是一個形狀相似標籤,一個挨一個的排列的元素。我將它的尺寸等屬性抽出來命名爲label,而後把佈局的屬性組命名爲float-left,若是個人設計風格是扁平化的,我能夠把相關的皮膚屬性命名爲flat,你知道雖然扁平化通常用不着特別的屬性,但我也能夠寫一些強制去掉圓角和漸變背景的屬性。做爲步驟,會分爲當前的步驟,以前的步驟,以及還沒到的步驟,當前的步驟能夠命名爲current,或者is—active,後面的步驟不能點因此能夠命名爲is-disable,這些都是狀態。而如今咱們來看看當前步驟元素是什麼樣的

<div class="flat label float-left is-active"></div>

總結成一句話就是「The flat label which float left is active」。這就是語義化的CSS。把組織好的語塊像說話同樣做用於元素上,對元素髮出指令,讓其變成想要的樣式。並且你應該會發現,一組該元素所獨有的屬性,或者是尺寸之類的通常是主語,佈局是動賓短語,而皮膚可能是一些形容詞,最後狀態能夠用表語。

總之,CSS做爲一個描述性的語言,有不少人以爲不能算一種語言,但我反而以爲這是一種高級語言,由於更接近天然語言。固然其主要做用是在視覺渲染上,因此應該是一種受限的語言,能夠看做是接近天然語言的子集。因此它的性質以爲了其重語義輕語法的特色,寫CSS不能僅靠語法規則,必定要用上語義規則,最好是能和項目中全部人達成共識,CSS框架其實就是一種通用共識。


原文

相關文章
相關標籤/搜索