“結構永遠服從於功能,這是不變的法則”,建築工程師“摩天大樓之父”Louis Sullivan如是說。因為工程師不希望讓無辜的人們被碾壓在巨大的建築物下,這種大拇指式的規則是相當有用的。在設計中你應該總是以功能為重,然後讓結構在結果中呈現。如果你以結構為重,雖然這能夠建造出一棟漂亮的摩天大樓,但代價是埋下了許多相當危險的種子。
這些都是關於建築師的,那麼對前端架構師或者“非真正的架構師”來說呢?我們需要遵守這個法則還是忽略它?
隨著面向對象的CSS(OOCSS)的出現,越來越多人趨向於“把呈現的語義從文檔語義中脫離出來”。借助於類(classes)的非特指含義,我們能夠以分離的方式來管理一個文檔和一個文檔的外貌。
在這篇文章當中,我們會探索多種為Web文檔添加樣式的方法,他們能把文檔語義與視覺設計相結合在一起。通過“聰明的”選擇器的使用,我們通過這種方法給你講解怎樣去查詢語義化的Html文檔現有的功能特性,以此作為對那些格式良好的標記的一個獎勵。如果你的代碼是正確的,你一定會得到你所期望設計出來的東西。
我想,如果你和我一樣同時在開發幾個不同的項目,我希望通過這些方法會簡化你的工作流程和並能更輕松地穿梭在這些項目當中。另外,在最後的部分我們 會講解一個更被動的方法:我們會制作一個包含屬性選擇器的CSS書簽來測試那些寫得很糟糕的Html文檔並使用偽元素來反饋錯誤。
樣式表的發明使我們能夠將那些美化HTML文檔的代碼從HTML文檔中分離出來。但它對於我們書寫標准的Html文檔方面所帶來的幫助並不像遙控器 那樣為電視機帶來了更高質量的電視節目。它只不過把工作變得更加簡單。因為我們能夠使用一個選擇器來為多個元素添加樣式。(例如 p 可作用於所有的段落元素),頁面的一致性和可維護性也不像以前那樣那麼令人畏懼。
p 選擇器最簡單的形式就是智能選擇器的一個代表。因為 p 選擇器在語義分類方面具有先天的基礎。不用開發者多做額外的事情它已經知道怎樣確認一個段落以及何時為他們添加樣式,非常簡單而有效,特別是你想為所見即所得編輯器產生的所有的段落元素添加樣式的時候。
但如果說它是智能的選擇器,那非智能的選擇器又是哪些呢?所有需要開發者介入並更改文檔從而引起樣式上的變化的選擇器都被稱之為非智能的選擇器。class 便是一個經典的非智能選擇器因為它不是作為語義約定的一部分出現的。你可以靈活地命名和組織類,但需要一定的思考;除非你在文檔上應用它們,否則它們不會自動地執行任何事情。
使用非智能選擇器是很消耗開發時間的,因為我們需要手動地為每一個選擇器添加對應的不同的樣式並把類名復制到每一個需要應用此類的元素。如果我們沒有 p 標簽,我們不得不使用非智能選擇器來管理段落,例如在每一個段落元素中使用一個 .paragraph
類來指明。這樣做的其中一個缺點是這些樣式表不是可移植的,因為你不能再沒有為Html文檔的標簽指定相應的類名的情況下而應用這些樣式到所需要的元素當中。
非智能選擇器有時候還是有必要的,並且我們很少人會完全依賴智能選擇器。然而,一些非智能選擇器可能會因為在文檔的結構和表現之間搭配不當而變成“愚蠢的”選擇器。我將會談論.button
這個使用頻率極高的“愚蠢”的選擇器。
智能選擇器並不限制於Html規范中所提供給我們的基礎元素。想要構建復雜的智能選擇器,你可以遵從上下文和功能屬性的組合來區分基礎元素。一些元素,例如<a>
,提供了大量的功能差異給開發者考慮和利用。其他的元素,例如<p>
元素,任何情景中在明確的功能上沒什麼差異,但也會根據上下文來承擔輕微不同的角色。
header p { /* styles for prologic paragraphs */ } footer p { /* styles for epilogic paragraphs */ }
像這樣的簡單後代選擇器是非常有用的,因為它們讓我們能夠從視覺上看出一個元素的不同類型而無需從物理上更改底層的文檔。這是整個樣式表發明的原因:既促進物理上的分離而又無需破壞那些存在於文檔和設計之間的概念上的相互關系。
不可避免的,一些OOCSS的粉絲們對這樣的後代選擇器是有點不太認同的,它們更喜歡像下面這個例子那樣來做標記,這是從BEM的“定義”文檔中找到的。
1 <ul class="menu"> 2 <li class="menu__item">…</li> 3 <li class="menu__item">…</li> 4 </ul>
我不會再對後代選擇器作進一步的討論,因為我確定你每天都在使用它們,除非你偏好於上面這種過量的概述。換言之,我們接下來會集中於屬性選擇器和屬性中描述的功能所帶來的差異。
即使是那些CSS和Html之間的概念分離的擁護者也樂於承認一些屬性——除了類和自定義數據屬性以外的大多數的屬性,實際上和文檔的內部工作的有重要關系的。沒有href
屬性你的超鏈接不會鏈接到任何東西。沒有type
屬性,浏覽器無法知道渲染哪一個類型的input元素。沒有title
屬性,你的abbr
元素則可能代表任何東西。
像這樣的屬性有助於改善文檔細節的語義化,否則你需要去確認主題元素是否正確被渲染以及運作。如果它們不存在,那麼它們應該被創造,如果它們已經存在了,那為什麼不適用它們呢?你不能夠只寫CSS而不寫Html吧。
REL屬性
rel
屬性是鏈接關系的一個標准屬性,是一個描述鏈接的具體的用途的一個方法。並不是所有的鏈接的功能都是相同的。得益於眾多的WordPress的使用者,rel="prev"
和rel="next"
成為兩個最廣泛采用的值,並有助於描述分頁博客內容的每個單獨頁面之間的關系。從語義上來說,一個擁有rel
屬性的a標簽仍然是一個a
標簽,但我們已經能更加具體地表現它了。這和類不相同,這種具體是從語義上間接表現的。
rel
屬性應該只被用在合適的地方,因為它們是被Html的功能規范所維護的,並能因此被不同的用戶代理采用從而提高用戶體驗和搜索引擎的精確度。那麼,你曾像下面這樣為鏈接添加過樣式嗎?使用簡單的屬性選擇器,如:
[rel="prev"] { /* styling for "previous links" */ } [rel="next"] { /* styling for "next" links */ }
屬性選擇器被所有的浏覽器所支持除了最古老和落後的浏覽器(IE6),因此只要這個屬性存在於標簽中的時候沒有任何理由不去使用它們。在它的優先級方面,它和類具有相同的權重值。然而,我記得它被建議,我們應該將文檔和表現語義分離。我不想浪費這個rel
屬性,所以我最好元素設置一個毫無意義的屬性並通過它來進行樣式的添加。
1 <a href="/previous-article-snippet/" rel="prev" class="prev">previous page</a>
此處首先要注意的第一件事情是,上面元素中唯一沒有對文檔的語義有幫助的是類這個屬性。換句話說,類在上面的文檔中式唯一的沒有起到什麼功能上的作用的東西。在實際中,這意味著類是唯一的打破了分離定律的並被解釋為:它實際存在於文檔中卻又沒對文檔的結構有任何幫助。
好了,說了這麼多抽象的概念,但它的可維護性方面如何?大家都接受使用class
作為樣式鉤子,讓我們看看當通過編輯或重構時移除了一些屬性的時候會發生什麼事情。假設我們使用了偽元素來為[rel="prev"]
鏈接的文字前面添加一個左指箭頭:
1 .prev:before { 2 content: '\2190'; /* encoding for a left-pointing arrow ("←") */ 3 }
移除類的同時也會同時移除了偽元素,反過來說這個舉動會將箭頭所移除。但沒有了這個箭頭,將沒有其他的東西能告訴我們鏈接現存的prev
關系。出於同樣的原因,移除rel
屬性也會導致箭頭的不完整:因為雖然class
會繼續讓這個箭頭得以顯示,卻總是使文檔的狀態關系丟失。只有直接的通過語義的屬性來給出樣式並應用,你才能讓你的代碼和你自己保持真實。只要是文檔中存在的真實的功能,你就要讓它被看見。
我可以想象你正在想什麼:“這很有趣,但在超鏈接中有多少個這樣的語義樣式鉤子?我還是會不得不依賴類來應用樣式。”那麼請你看看下面不同的鏈接功能的不完全的列表吧,所有都是以a
元素為基礎的:
這就是鏈接功能上的差異,所有的類型都可以被用戶代理所識別。現在讓我們思考一個問題,為了讓所有的這些具體鏈接類型都執行不同的功能,它們必須要 有不同的屬性。也就是說,為了執行不同的功能,鏈接的書寫形式是需要有所變化的;並且,如果它們書寫形式不同,它們就可以通過這個來添加不同的樣式。
在准備這篇文章的時候,我對一個構思作了一個檢驗,命名為Auticons。Auticons是一個圖標字體和樣式表,用於自動地為鏈接添加樣式。裡面的所有選擇器都是屬性選擇器而沒有一個類,為格式良好的超鏈接來調用樣式。
在許多的案例中,Auticons 對href
值的一個子集進行了查詢來確定超鏈接的功能。通過的它們的屬性值的開頭或結尾來對相應的元素添加樣式,又或者是根據它們屬性值是否包含了一個指定的字串來查找對應元素也是可能的。下面是一些常普通的例子。
安全協議 每一個格式良好的URL(例如:絕對地址的URL)會以一個URI scheme 加一個冒號開始。在網絡中我們最常見的就是http:
,但是mailTo:
(用於簡單郵件傳輸協議SMTP)和tel:
(用於電話號碼)也是很常用的。如果我們可以知道超鏈接的href
的值會如何開始,我們可以利用這個約定來作為樣式鉤子。在下面的用於安全頁面的例子,我們使用^=
比較器,意思為“以...開始”。
1 [href^="https:"] { 2 /* style propertIEs exclusive to secure pages */ 3 }
在Auticons 中,根據一個特定的用於識別href
屬性的語義模式,連到安全頁面的鏈接用一把鎖來做裝飾。這樣做的優點是:
http
協議同時用作比喻的掛鎖也會消失。
當應用於動態內容的時候,這個選擇器顯得相當地智能。因為安全鏈接具有它特定的URI scheme,所以屬性選擇器能夠預料到它的調用:一旦編輯器鍵入一些包含安全鏈接的內容,鏈接便會自動應用樣式來給予用戶一個它是一個安全鏈接的感覺。 因為不需要什麼類以及對Html進行編輯,所以簡單的Markdown 中的鏈接是這樣的:
[Link to secure page](https://payment.example.com/)
但要注意的是使用 [href^="https:"]
也不是永遠正確的,因為也不是所有的 HTTPS 真正安全的。不過,這僅僅是當浏覽器本身不太可靠的情況下。專業的浏覽器都會在顯示 HTTPS 的時候在地址欄渲染一個掛鎖。
文件類型
正如我說過的,你也可以通過 href
屬性以什麼結尾來為超鏈接添加樣式。在實踐中,這意味著你可以使用CSS來指出鏈接所指向的文件類型。Auticons 支持.txt
, .pdf
, .doc
, .exe
和其他的一些格式,下面是.zip
格式的一個例子,使用$=
來決定href
以什麼結尾:
1 [href$=".zip"]:before, 2 [href$=".gz"]:before { 3 content: '\E004'; /* unicode for the zip folder icon */ 4 }
組合
你知道如何在一個元素中添加多個類的方法來建立樣式吧?很好,其實你可以用屬性選擇器來幫你自動完成這些工作。讓我們來對比一下:
/* The CSS for the class approach */ .new-window-icon:after { content: '[new window icon]'; } .twitter-icon:before { content: '[twitter icon]'; } /* The CSS for the attribute selector approach */ [target="_blank"]:after { content: '[new window icon]'; } [href*="twitter.com/"]:before { content: '[twitter icon]'; }
(注意,*=
比較器的意思是“內容”,如果href
的值包含字串twitter.com/
,那麼樣式便會應該到該元素上)
<!-- The HTML for the class approach --> <a href="http://twitter.com/heydonworks" target="_blank" class="new-window-icon twitter-icon">@heydonworks</a> <!-- The Html for the attribute selector approach --> <a href="http://twitter.com/heydonworks" target="_blank">@heydonworks</a>
任何負責添加一個到Twitter 頁面的超鏈接的內容編輯器,現在只需要知道兩件事:URL和如何在新標簽中打開。因為屬性選擇器能幫助他們找到對應的超鏈接。
繼承
還有一些沒有考慮到的地方是:如果有一個不匹配任何屬性選擇器的鏈接呢?如果這個超鏈接是一個普通的舊超鏈接呢?這個選擇器是一個很容易被記住的並且追求性能極致的人會很樂意聽到這種話“已經沒有別的比它還要更簡練了”。
層疊的屬性選擇器的繼承性與和類層疊在一起的時候是一樣的。首先,它會對你的a
添加樣式 —— 假設是一個 text-decoration: underline
規則來提高鏈接的可訪問性;然後使用你所提供的屬性選擇器來為相應的a
元素進一步添加層疊的樣式。像IE7 這樣的浏覽器並不完全支持偽元素。但因為繼承的關系,鏈接還是會應用a
選擇器中的樣式。
a { color: blue; text-decoration: underline; } a[rel="external"]:after { content: '[icon for external links]'; }
在下面的部分,我們會詳述我們這個CSS書簽的結構來講解代碼上的錯誤。在做這件事前,首先讓我們來看看可能會有什麼糟糕的選擇器潛入我們的工作流程中。
OOCSS的信徒們仍然堅持使用類因為它們是可重用的,就像組件一樣。因此,.button
比#button
更好。不過,我能想到更好的按鈕樣式的選擇器。它的名字也很容易記住。
The <buttonelement represents a button. – W3C Wiki
Topcoat是一個OOCSS的基於BEM的UI框架,來自Adobe。Topcoat中的各種各樣的按鈕樣式代碼超過了450行,如果把注釋塊也加進去的話。裡面的注釋塊建議我們用類似這個例子的方式來應用按鈕的樣式。
1 <a class="topcoat-button">Button</a>
這個不是一個button。因為,如果它是一個按鈕,應該是使用<button>
來做標簽。實際上,在每一個我們已知的浏覽器中,如果使用<button>
來表現一個按鈕而不添加任何樣式,它默認看起來也會像一個按鈕。但上面這個例子不是的,因為它用的是<a>
標簽,本應該是代表一個超鏈接,實際上,它缺少一個href
,這意味著它甚至不算是一個超鏈接。在技術上,它只是一個占位符,一個沒有完成的不完整的超鏈接。
一只穿著鲨魚服裝的小狗並不是鲨魚
Topcoat的CSS中的示例僅僅是一個范例,但前提是類定義了元素並且Html不是欺騙性的(你應該使用button標簽而不是a標簽來描述按鈕)。再多的“有意義的斷字”的類名添加也不能彌補你這樣丑陋地使用非智能選擇器和犯下的代碼上的錯誤。
更新:因為寫了這篇文章,Topcoat.io 已經使用<button>
標簽來取代上面那個例子。這簡直太棒了!然而,我對它們使用.is-disabled
類來指明這個按鈕是禁用的而忽略了disabled
屬性持保留意見。你可以在評論區看到我和Topcoat 的代表在這方面的討論。對與促進OOCSS 所帶來的WEB標准的災難,你可以在 semantic-ui.com中自行發現,它們示例中的“標准按鈕”居然是一個包含空的<i>
標簽的<div>
標簽。
看見是麼就是什麼
“如果它看起來像只鴨,游泳時也像只鴨,叫聲也像只鴨,那麼它可能是一只鴨。”
一個裝飾得像按鈕一樣的鏈接,並且還能觸發像點擊按鈕那樣的Javascript 事件,對很多人來說,它是一個按鈕。然而,這只意味著它已經通過了前兩個階段的“鴨測試”。為了讓所有的用戶能夠運用歸納推理和辨別按鈕,它也必須像這 樣。因為它仍然是一個鏈接,盡量避免這種不必要的混淆,因為這種輔助技術的使用者沒有追求一個完美語義但這又恰好是我們應當承擔的職責。
盡管如此,有些人還是堅持用a
作為按鈕的標簽。超鏈接是比較容易完全重新地樣式化的一個元素。如果選擇a
標簽作為元素,那麼只有一個辦法讓它接近真正的按鈕。你猜對了:你必須使用WAI ARIA role 屬性值來指明它的含義。可以僅僅通過下列的屬性選擇器來確認一個超鏈接因為某些原因看起來像是一個按鈕。
1 [role="button"] { 2 /* semantic CSS for modified elements that are announced as “button” in assistive technologIEs */ 3 }
“CSS給予了class 屬性強大的力量,作者可以基於那些沒有任何表現的元素(例如DIV和SPAN)在想象中設計他們的“文檔語言”,並通過class 屬性來賦予他們樣式信息。作者應該避免這種行為即使這種文檔語言的結構元素經常得到大家認可和接受它們的意義。” – “選擇器,” CSS Level 2, W3C
我們具有a
和 button
兩個元素的原因是為了在語義上劃分兩種完全不同的功能交互。超鏈接代表著你將會去到的某個位置的符號,而按鈕是作為事件或者動作的觸發源。一個是關於位置移動的,另一個則是側重於轉換的。一個是促進脫離的,另一個是促進結合的。
為了確保我們不會做什麼愚蠢的事情來讓我們的按鈕和超鏈接產生混淆。我們會創建一個使用智能屬性選擇器的CSS書簽並來測試兩個元素各自的有效性和質量。
受到Eric Meyer的文章的一點啟發以及從DiagnostiCSS 中獲取了一些線索,這個樣式表會結合屬性選擇器和:not
選擇器(或者非偽類) 來在Html 中把問題高亮出來。與其他的兩種實現不同,它會使用偽元素來將錯誤打印到屏幕上。每一個錯誤都會采用漫畫字體以及粉紅色的背景來顯示。
通過把功能和表單連接起來,我們可以看到丑陋的Html 會間接地導致丑陋的 CSS。這是設計師濫用文檔帶來的後果。嘗試一下把revenge.CSS
保存到你的CSS書簽中,並單擊這個書簽以在任何你喜歡的頁面觸發它。注意:它不會在服務在https協議上的頁面中起作用。
規則1
如果它是個超鏈接,那它就應該有
href
屬性。
a:not([href]):after { content: 'Do you mean for this to be a link or a button, because it does not link to anything!'; display: block !important; background: pink !important; padding: 0.5em !important; font-family: 'comic sans ms', cursive !important; color: #000 !important; font-size: 16px !important; }
注意:在這個例子中我並不是要測試屬性的值,而是測試這個屬性是否有被設置,也就是說,[href]匹配的是任何含有href屬性的元素。這個測試僅僅適用於超鏈接。這個測試可以這樣來理解,“對於每一個不具有href屬性的元素,為其添加一個偽元素並在偽元素中報告錯誤提示。”
規則2
“如果這個超鏈接具有href屬性,那這個屬性應該具有值。”
1 a[href=""]:after, a[href$="#"]:after, a[href^="Javascript"]:after {
2 content: 'Do you mean for this link to be a button, because it does not go anywhere!';
3 /*... ugly styles ...*/
4 }
注意:如果這個href屬性的值為空或者以# 結尾又或者是使用Javascript,那麼它應該是被用作了非<button>標簽實現的按鈕。注意我使用的是“以Javascript開始”,這樣可以避免其使用的是Javascript:void(0)這樣的值。但我們也不能指望它總是以這種方式書寫。
規則3
“如果它使用了button 類,那它理應是一個按鈕,至少在可訪問性層上。”
1 .button:not(button):not([role="button"]):not([type="button"]):not([type="submit"]):not([type="reset"]):after,
2 .btn:not(button):not([role="button"]):not([type="button"]):not([type="submit"]):not([type="reset"]):after,
3 a[class*="button"]:not([role="button"]):after {
4 content: 'If you are going to make it look like a button, make it a button, damn it!';
5 /*... ugly styles ...*/
6 }
注意:這個例子中,我們為你展示了,當測試屬性值的時候,你可以怎樣來使用鏈式的否定。每一個選擇器可以像這樣理解:“如果一個元素具有一個類指明它是一個按鈕,但它卻不是一個按鈕元素,並且沒有一個正確的role 值來使它在可訪問性層為一個按鈕,而且它也不是一個按鈕類型的input元素,那好吧。。。你在說謊。”我不得不使用[class*="button"]來捕獲Topcoat 裡面沒有使用role來成為實際按鈕的超鏈接中應用的不同的類(多達62種!)。我注意到有一些開發者在按鈕的父元素上使用button-container和其他相似的類名,這就是為什麼a修飾符被包含在裡面的原因。你可以注意到在Twitter Bootstrap 中使用了.btn類,(如果你仔細閱讀了它的組件文檔)你會知道這無法確定是否使用鏈接還是按鈕來作為按鈕。
規則4
如果一個元素具有role="button",那麼即使沒有Javascript它也應該能鏈接到某個地方。
1 a[role="button"]:not([href*="/"]):not([href*="."]):not([href*="?"]):after {
2 content: 'Either use a link fallback, or just use a button element.';
3 /*... ugly styles ...*/
4 }
注意:我們可以相當地確定不包含/,.(通常存在於文件拓展名的前面)或?(查詢字符串的開端)其中之一的href應該是假的。使鏈接表現地像按鈕並且當Javascript開啟並return: false的時候是很好的。原因是,當Javascript關閉時它也能夠鏈接到某個地方。實際上,這僅僅是我能夠想出來的不使用<button>的一個合理的理由。
規則5
“你不能夠禁用一個超鏈接。”
1 a.button[class*="disabled"]:after,
2 a.btn.disabled:after,
3 a[class*="button"][class*="disabled"]:after {
4 content: 'You cannot disable a hyperlink. Use a button element with disabled="disabled".';
5 /*... ugly styles ...*/
6 }
注意:甚至連很古老的用戶代理也能識別disabled屬性,因此我們可以恰當地把使用在一些合適的元素中。上面的例子可以看出,你可以連接屬性選擇器,就好像你連接多個類一樣:在最後的三個選擇器,我們聲明,“如果一個超鏈接的類中包含button字串和disabled字串,就會為其打印錯誤信息。”Twitter Bootstrap 使用第二種形式,.btn.disabled,在它的樣式表中,但並不包含a前綴。如果是用在超鏈接中我們只會認為它是一個錯誤。
規則6
“在表單中的按鈕應該具有明確的類型。”
1 form button:not([type]):after {
2 content: 'Is this a submit button, a reset button or what? Use type="submit", type="reset" or type="button"';
3 }
注意:我們需要確定表單中的按鈕是否具有明確的類型,因為一些浏覽器會把所有沒有明確類型的button元素設置為type="submit"。如果我們表單中的按鈕具有其它的母的,我們必須絕對保證該按鈕的類型不是submit。
規則7
“無論是按鈕還是超鏈接都應該具有一些內容在裡面或者是具有ARIA label。”
a:empty:not([aria-label]):not([aria-labelledby]):after,
button:empty:not([aria-label]):not([aria-labelledby]):after,
button:not([aria-label]):not([aria-labelledby]) img:only-child:not([alt]):after,
a:not([aria-label]):not([aria-labelledby]) img:only-child:not([alt]):after {
content: 'All buttons and links should have text content, an image with alt text or an ARIA label';
/*... ugly styles ...*/
}
注意:按鈕和鏈接並沒有什麼明確的用途 —— 在文本和圖像的形式上 —— 是相當假的。最後的兩個選擇器是我寫過的最復雜的選擇器了。對於超鏈接的版本,這個選擇器應該是這樣理解的,“如果一個超鏈接不具有aria-label
屬性或aria-labelledby
屬性,並且它只包含一個圖片元素作為內容,但這個圖片又不具有alt
屬性,那就會打印相關的錯誤信息。”另外,注意這個“:empty
選擇器”。存在爭論的是,那些非自動閉合的元素永遠不該被置為空。
在上面的例子中我所用來描述的這些選擇器和模式並不是想嘗試一些不同的而寫一些東西。屬性選擇器也不是什麼新鮮事物。IE 6是唯一的不支持它的浏覽器。我使用它們的原因是我沒有時間和精力在CSS上寫了一遍選擇器還要在完全地在Html在寫一遍。我在我的頁面的頭部使用[role="banner"]
而不使用.page-header
是因為這是我唯一知道的方法 —— 基於能看到預期的視覺效果 —— 並能夠把導航標志放在正確的位置。
沒有所謂的語義的CSS,只存在語義的Html 和它的可見形式。在這篇文章中我已經展示了這些東西,通過將web頁面的功能和構成直接地結合,你可以建立獎勵和懲罰的機制。一方面,你可以設置選擇器對 那些被正確使用的標簽來添加可見的圖案;另一方面,你可以找到那些丑陋的錯誤的方式應用的標簽結構並在頁面上打印它們的錯誤。
老實的說,並不是所有的樣式鉤子都是完全語義的和智能的。類被描述為一些需要應用的元素以及尚未成為標准的屬性的填充物。因此你可以發現 .footer
變成了 <footer>
以及 type="text"
(通過Javascript來驗證url)變為可以直接使用type="url"
來驗證url 。其他時候,它在做非語義的布局基於網格框架的腳手架時是非常有用的。
然而,當你決定給予CSS自己完全獨立的邏輯時,在功能和結構之間一定會產生不必要的爭執。在這種情況下,你只有提高自己的警惕才能讓它們不會難以理解和失去效果。更糟糕的是,追求寫完全語義化的類的時候往往會讓你陷入“什麼是語義化的類”的沒完沒了的討論當中。你會開始用更少的時間來用遙控器操作電視機而變得花費更多時間站在前面,思考如何使用你的遙控器。
生命很短,請珍惜時間。
譯者手語:整個翻譯依照原文線路進行,並在翻譯過程略加了個人對技術的理解。如果翻譯有不對之處,還煩請同行朋友指點。謝謝!