智能選擇器和語(yǔ)義化的CSS
2015-10-08 來(lái)自: 陜西印象信息技術(shù)有限公司 瀏覽次數:3449
“結構***服從于功能,這是不變的法則”,建筑工程師“摩天大樓之父”Louis Sullivan如是說(shuō)。因為工程師不希望讓無(wú)辜的人們被碾壓在巨大的建筑物下,這種大拇指式的規則是相當有用的。在設計中你應該總是以功能為重,然后讓結構在結果中呈現。如果你以結構為重,雖然這能夠建造出一棟漂亮的摩天大樓,但代價(jià)是埋下了許多相當危險的種子。
這些都是關(guān)于建筑師的,那么對前端架構師或者“非真正的架構師”來(lái)說(shuō)呢?我們需要遵守這個(gè)法則還是忽略它?
隨著(zhù)面向對象的CSS(OOCSS)的出現,越來(lái)越多人趨向于“把呈現的語(yǔ)義從文檔語(yǔ)義中脫離出來(lái)”。借助于類(lèi)(classes)的非特指含義,我們能夠以分離的方式來(lái)管理一個(gè)文檔和一個(gè)文檔的外貌。
在這篇文章當中,我們會(huì )探索多種為Web文檔添加樣式的方法,他們能把文檔語(yǔ)義與視覺(jué)設計相結合在一起。通過(guò)“聰明的”選擇器的使用,我們通過(guò)這種方法給你講解怎樣去查詢(xún)語(yǔ)義化的HTML文檔現有的功能特性,以此作為對那些格式良好的標記的一個(gè)獎勵。如果你的代碼是正確的,你***會(huì )得到你所期望設計出來(lái)的東西。
我想,如果你和我一樣同時(shí)在開(kāi)發(fā)幾個(gè)不同的項目,我希望通過(guò)這些方法會(huì )簡(jiǎn)化你的工作流程和并能更輕松地穿梭在這些項目當中。另外,在最后的部分我們 會(huì )講解一個(gè)更被動(dòng)的方法:我們會(huì )制作一個(gè)包含屬性選擇器的CSS書(shū)簽來(lái)測試那些寫(xiě)得很糟糕的HTML文檔并使用偽元素來(lái)反饋錯誤。
聰明的選擇器
樣式表的發(fā)明使我們能夠將那些美化HTML文檔的代碼從HTML文檔中分離出來(lái)。但它對于我們書(shū)寫(xiě)標準的HTML文檔方面所帶來(lái)的幫助并不像遙控器 那樣為電視機帶來(lái)了更高質(zhì)量的電視節目。它只不過(guò)把工作變得更加簡(jiǎn)單。因為我們能夠使用一個(gè)選擇器來(lái)為多個(gè)元素添加樣式。(例如 p 可作用于所有的段落元素),頁(yè)面的一致性和可維護性也不像以前那樣那么令人畏懼。
p 選擇器的形式就是智能選擇器的一個(gè)代表。因為 p 選擇器在語(yǔ)義分類(lèi)方面具有先天的基礎。不用開(kāi)發(fā)者多做額外的事情它已經(jīng)知道怎樣確認一個(gè)段落以及何時(shí)為他們添加樣式,非常簡(jiǎn)單而有效,特別是你想為所見(jiàn)即所得編輯器產(chǎn)生的所有的段落元素添加樣式的時(shí)候。
但如果說(shuō)它是智能的選擇器,那非智能的選擇器又是哪些呢?所有需要開(kāi)發(fā)者介入并更改文檔從而引起樣式上的變化的選擇器都被稱(chēng)之為非智能的選擇器。class 便是一個(gè)經(jīng)典的非智能選擇器因為它不是作為語(yǔ)義約定的一部分出現的。你可以靈活地命名和組織類(lèi),但需要***的思考;除非你在文檔上應用它們,否則它們不會(huì )自動(dòng)地執行任何事情。
使用非智能選擇器是很消耗開(kāi)發(fā)時(shí)間的,因為我們需要手動(dòng)地為每一個(gè)選擇器添加對應的不同的樣式并把類(lèi)名復制到每一個(gè)需要應用此類(lèi)的元素。如果我們沒(méi)有 p 標簽,我們不得不使用非智能選擇器來(lái)管理段落,例如在每一個(gè)段落元素中使用一個(gè) .paragraph類(lèi)來(lái)指明。這樣做的其中一個(gè)缺點(diǎn)是這些樣式表不是可移植的,因為你不能再沒(méi)有為HTML文檔的標簽指定相應的類(lèi)名的情況下而應用這些樣式到所需要的元素當中。
非智能選擇器有時(shí)候還是有必要的,并且我們很少人會(huì )完全依賴(lài)智能選擇器。然而,一些非智能選擇器可能會(huì )因為在文檔的結構和表現之間搭配不當而變成“愚蠢的”選擇器。我將會(huì )談?wù)?button這個(gè)使用頻率極高的“愚蠢”的選擇器。
不同組合的好處
智能選擇器并不限制于HTML規范中所提供給我們的基礎元素。想要構建復雜的智能選擇器,你可以遵從上下文和功能屬性的組合來(lái)區分基礎元素。一些元素,例如<a>,提供了大量的功能差異給開(kāi)發(fā)者考慮和利用。其他的元素,例如<p>元素,任何情景中在明確的功能上沒(méi)什么差異,但也會(huì )根據上下文來(lái)承擔輕微不同的角色。
header p {
/* styles for prologic paragraphs */
}
footer p {
/* styles for epilogic paragraphs */
}
像這樣的簡(jiǎn)單后代選擇器是非常有用的,因為它們讓我們能夠從視覺(jué)上看出一個(gè)元素的不同類(lèi)型而無(wú)需從物理上更改底層的文檔。這是整個(gè)樣式表發(fā)明的原因:既促進(jìn)物理上的分離而又無(wú)需破壞那些存在于文檔和設計之間的概念上的相互關(guān)系。
不可避免的,一些OOCSS的粉絲們對這樣的后代選擇器是有點(diǎn)不太認同的,它們更喜歡像下面這個(gè)例子那樣來(lái)做標記,這是從BEM的“定義”文檔中找到的。
1 <ul class="menu"> 2 <li class="menu__item">…</li> 3 <li class="menu__item">…</li> 4 </ul>
我不會(huì )再對后代選擇器作進(jìn)一步的討論,因為我確定你每天都在使用它們,除非你偏好于上面這種過(guò)量的概述。換言之,我們接下來(lái)會(huì )集中于屬性選擇器和屬性中描述的功能所帶來(lái)的差異。
超鏈接屬性
即使是那些CSS和HTML之間的概念分離的擁護者也樂(lè )于承認一些屬性——除了類(lèi)和自定義數據屬性以外的大多數的屬性,實(shí)際上和文檔的內部工作的有重要關(guān)系的。沒(méi)有href屬性你的超鏈接不會(huì )鏈接到任何東西。沒(méi)有type屬性,瀏覽器無(wú)法知道渲染哪一個(gè)類(lèi)型的input元素。沒(méi)有title屬性,你的abbr元素則可能代表任何東西。
像這樣的屬性有助于改善文檔細節的語(yǔ)義化,否則你需要去確認主題元素是否正確被渲染以及運作。如果它們不存在,那么它們應該被創(chuàng )造,如果它們已經(jīng)存在了,那為什么不適用它們呢?你不能夠只寫(xiě)CSS而不寫(xiě)HTML吧。
REL屬性
rel屬性是鏈接關(guān)系的一個(gè)標準屬性,是一個(gè)描述鏈接的具體的用途的一個(gè)方法。并不是所有的鏈接的功能都是相同的。得益于眾多的WordPress的使用者,rel="prev"和rel="next"成為兩個(gè)***廣泛采用的值,并有助于描述分頁(yè)博客內容的每個(gè)單獨頁(yè)面之間的關(guān)系。從語(yǔ)義上來(lái)說(shuō),一個(gè)擁有rel屬性的a標簽仍然是一個(gè)a標簽,但我們已經(jīng)能更加具體地表現它了。這和類(lèi)不相同,這種具體是從語(yǔ)義上間接表現的。
rel屬性應該只被用在合適的地方,因為它們是被HTML的功能規范所維護的,并能因此被不同的用戶(hù)代理采用從而提高用戶(hù)體驗和搜索引擎的精que度。那么,你曾像下面這樣為鏈接添加過(guò)樣式嗎?使用簡(jiǎn)單的屬性選擇器,如:
[rel="prev"] {
/* styling for "previous links" */
}
[rel="next"] {
/* styling for "next" links */
}
屬性選擇器被所有的瀏覽器所支持除了***古老和落后的瀏覽器(IE6),因此只要這個(gè)屬性存在于標簽中的時(shí)候沒(méi)有任何理由不去使用它們。在它的優(yōu)先級方面,它和類(lèi)具有相同的權重值。然而,我記得它被建議,我們應該將文檔和表現語(yǔ)義分離。我不想浪費這個(gè)rel屬性,所以我***hao元素設置一個(gè)毫無(wú)意義的屬性并通過(guò)它來(lái)進(jìn)行樣式的添加。
1 <a href="/previous-article-snippet/" rel="prev" class="prev">previous page</a>
此處首先要注意的第1件事情是,上面元素中唯yi沒(méi)有對文檔的語(yǔ)義有幫助的是類(lèi)這個(gè)屬性。換句話(huà)說(shuō),類(lèi)在上面的文檔中式唯yi的沒(méi)有起到什么功能上的作用的東西。在實(shí)際中,這意味著(zhù)類(lèi)是唯yi的打破了分離定律的并被解釋為:它實(shí)際存在于文檔中卻又沒(méi)對文檔的結構有任何幫助。
好了,說(shuō)了這么多抽象的概念,但它的可維護性方面如何?大家都接受使用class作為樣式鉤子,讓我們看看當通過(guò)編輯或重構時(shí)移除了一些屬性的時(shí)候會(huì )發(fā)生什么事情。假設我們使用了偽元素來(lái)為[rel="prev"]鏈接的文字前面添加一個(gè)左指箭頭:
1 .prev:before {2 content: '\2190'; /* encoding for a left-pointing arrow ("←") */3 }
移除類(lèi)的同時(shí)也會(huì )同時(shí)移除了偽元素,反過(guò)來(lái)說(shuō)這個(gè)舉動(dòng)會(huì )將箭頭所移除。但沒(méi)有了這個(gè)箭頭,將沒(méi)有其他的東西能告訴我們鏈接現存的prev關(guān)系。出于同樣的原因,移除rel屬性也會(huì )導致箭頭的不完整:因為雖然class會(huì )繼續讓這個(gè)箭頭得以顯示,卻總是使文檔的狀態(tài)關(guān)系丟失。只有直接的通過(guò)語(yǔ)義的屬性來(lái)給出樣式并應用,你才能讓你的代碼和你自己保持真實(shí)。只要是文檔中存在的真實(shí)的功能,你就要讓它被看見(jiàn)。
屬性字串
我可以想象你正在想什么:“這很有趣,但在超鏈接中有多少個(gè)這樣的語(yǔ)義樣式鉤子?我還是會(huì )不得不依賴(lài)類(lèi)來(lái)應用樣式?!蹦敲凑埬憧纯聪旅娌煌逆溄庸δ艿牟煌耆牧斜戆?,所有都是以a元素為基礎的:
links to external resources,
links to secure pages,
links to author pages,
links to help pages,
links to previous pages (see example above),
links to next pages (see example above again),
links to PDF resources,
links to documents,
links to ZIP folders,
links to executables,
links to internal page fragments,
links that are really buttons (more on these later),
links that are really buttons and are toggle-able,
links that open mail clients,
links that cue up telephone numbers on smartphones,
links to the source view of pages,
links that open new tabs and windows,
links to JavaScript and JSON files,
links to RSS feeds and XML files.
這就是鏈接功能上的差異,所有的類(lèi)型都可以被用戶(hù)代理所識別?,F在讓我們思考一個(gè)問(wèn)題,為了讓所有的這些具體鏈接類(lèi)型都執行不同的功能,它們***要 有不同的屬性。也就是說(shuō),為了執行不同的功能,鏈接的書(shū)寫(xiě)形式是需要有所變化的;并且,如果它們書(shū)寫(xiě)形式不同,它們就可以通過(guò)這個(gè)來(lái)添加不同的樣式。
在準備這篇文章的時(shí)候,我對一個(gè)構思作了一個(gè)檢驗,命名為Auticons。Auticons是一個(gè)圖標字體和樣式表,用于自動(dòng)地為鏈接添加樣式。里面的所有選擇器都是屬性選擇器而沒(méi)有一個(gè)類(lèi),為格式良好的超鏈接來(lái)調用樣式。
在許多的案例中,Auticons 對href值的一個(gè)子集進(jìn)行了查詢(xún)來(lái)確定超鏈接的功能。通過(guò)的它們的屬性值的開(kāi)頭或結尾來(lái)對相應的元素添加樣式,又或者是根據它們屬性值是否包含了一個(gè)指定的字串來(lái)查找對應元素也是可能的。下面是一些常普通的例子。
安全協(xié)議 每一個(gè)格式良好的URL(例如:絕dui地址的URL)會(huì )以一個(gè)URI scheme 加一個(gè)冒號開(kāi)始。在網(wǎng)絡(luò )中我們***常見(jiàn)的就是http:,但是mailTo:(用于簡(jiǎn)單郵件傳輸協(xié)議SMTP)和tel:(用于電話(huà)號碼)也是很常用的。如果我們可以知道超鏈接的href的值會(huì )如何開(kāi)始,我們可以利用這個(gè)約定來(lái)作為樣式鉤子。在下面的用于安全頁(yè)面的例子,我們使用^=比較器,意思為“以...開(kāi)始”。
1 [href^="https:"] {2 /* style properties exclusive to secure pages */3 }
在A(yíng)uticons 中,根據一個(gè)特定的用于識別href屬性的語(yǔ)義模式,連到安全頁(yè)面的鏈接用一把鎖來(lái)做裝飾。這樣做的優(yōu)點(diǎn)是:
安全頁(yè)面的鏈接 —— 也僅僅是安全頁(yè)面 —— 能夠通過(guò)一把掛鎖來(lái)作使它像是一個(gè)安全頁(yè)面鏈接。
那些不再鏈接到安全頁(yè)面的鏈接會(huì )失去http協(xié)議同時(shí)用作比喻的掛鎖也會(huì )消失。
新的安全頁(yè)面的鏈接也會(huì )自動(dòng)采用這個(gè)掛鎖來(lái)標志這個(gè)鏈接。
當應用于動(dòng)態(tài)內容的時(shí)候,這個(gè)選擇器顯得相當地智能。因為安全鏈接具有它特定的URI scheme,所以屬性選擇器能夠預料到它的調用:一旦編輯器鍵入一些包含安全鏈接的內容,鏈接便會(huì )自動(dòng)應用樣式來(lái)給予用戶(hù)一個(gè)它是一個(gè)安全鏈接的感覺(jué)。 因為不需要什么類(lèi)以及對HTML進(jìn)行編輯,所以簡(jiǎn)單的Markdown 中的鏈接是這樣的:
[Link to secure page](https://payment.example.com/)
但要注意的是使用 [href^="https:"]也不是***正確的,因為也不是所有的 HTTPS 真正***。不過(guò),這僅僅是當瀏覽器本身不太可靠的情況下。***瀏覽器都會(huì )在顯示 HTTPS 的時(shí)候在地址欄渲染一個(gè)掛鎖。
文件類(lèi)型
正如我說(shuō)過(guò)的,你也可以通過(guò) href屬性以什么結尾來(lái)為超鏈接添加樣式。在實(shí)踐中,這意味著(zhù)你可以使用CSS來(lái)指出鏈接所指向的文件類(lèi)型。Auticons 支持.txt, .pdf, .doc, .exe和其他的一些格式,下面是.zip格式的一個(gè)例子,使用$=來(lái)決定href以什么結尾:
1 [href$=".zip"]:before, 2 [href$=".gz"]:before {3 content: '\E004'; /* unicode for the zip folder icon */4 }
組合
你知道如何在一個(gè)元素中添加多個(gè)類(lèi)的方法來(lái)建立樣式吧?很好,其實(shí)你可以用屬性選擇器來(lái)幫你自動(dòng)完成這些工作。讓我們來(lái)對比一下:
/* 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/,那么樣式便會(huì )應該到該元素上)
<!-- 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>
任何負責添加一個(gè)到Twitter 頁(yè)面的超鏈接的內容編輯器,現在只需要知道兩件事:URL和如何在新標簽中打開(kāi)。因為屬性選擇器能幫助他們找到對應的超鏈接。
繼承
還有一些沒(méi)有考慮到的地方是:如果有一個(gè)不匹配任何屬性選擇器的鏈接呢?如果這個(gè)超鏈接是一個(gè)普通的舊超鏈接呢?這個(gè)選擇器是一個(gè)很容易被記住的并且追求性能極zhi的人會(huì )很樂(lè )意聽(tīng)到這種話(huà)“已經(jīng)沒(méi)有別的比它還要更簡(jiǎn)練了”。
層疊的屬性選擇器的繼承性與和類(lèi)層疊在一起的時(shí)候是一樣的。首先,它會(huì )對你的a添加樣式 —— 假設是一個(gè)text-decoration: underline規則來(lái)提高鏈接的可訪(fǎng)問(wèn)性;然后使用你所提供的屬性選擇器來(lái)為相應的a元素進(jìn)一步添加層疊的樣式。像IE7 這樣的瀏覽器并不完全支持偽元素。但因為繼承的關(guān)系,鏈接還是會(huì )應用a選擇器中的樣式。
a {
color: blue;
text-decoration: underline;
}
a[rel="external"]:after {
content: '[icon for external links]';
}
實(shí)際的按鈕應該是真實(shí)的
在下面的部分,我們會(huì )詳述我們這個(gè)CSS書(shū)簽的結構來(lái)講解代碼上的錯誤。在做這件事前,首先讓我們來(lái)看看可能會(huì )有什么糟糕的選擇器潛入我們的工作流程中。
OOCSS的信徒們仍然堅持使用類(lèi)因為它們是可重用的,就像組件一樣。因此,.button比#button***。不過(guò),我能想到***的按鈕樣式的選擇器。它的名字也很容易記住。
The <buttonelement represents a button. – W3C Wiki
Topcoat是一個(gè)OOCSS的基于BEM的UI框架,來(lái)自Adobe。Topcoat中的各種各樣的按鈕樣式代碼超過(guò)了450行,如果把注釋塊也加進(jìn)去的話(huà)。里面的注釋塊建議我們用類(lèi)似這個(gè)例子的方式來(lái)應用按鈕的樣式。
1 <a class="topcoat-button">Button</a>
這個(gè)不是一個(gè)button。因為,如果它是一個(gè)按鈕,應該是使用<button>來(lái)做標簽。實(shí)際上,在每一個(gè)我們已知的瀏覽器中,如果使用<button>來(lái)表現一個(gè)按鈕而不添加任何樣式,它默認看起來(lái)也會(huì )像一個(gè)按鈕。但上面這個(gè)例子不是的,因為它用的是<a>標簽,本應該是代表一個(gè)超鏈接,實(shí)際上,它缺少一個(gè)href,這意味著(zhù)它甚至不算是一個(gè)超鏈接。在技術(shù)上,它只是一個(gè)占位符,一個(gè)沒(méi)有完成的不完整的超鏈接。
一只穿著(zhù)鯊魚(yú)服裝的小狗并不是鯊魚(yú)
Topcoat的CSS中的示例僅僅是一個(gè)范例,但前提是類(lèi)定義了元素并且HTML不是欺騙性的(你應該使用button標簽而不是a標簽來(lái)描述按鈕)。再多的“有意義的斷字”的類(lèi)名添加也不能彌補你這樣丑陋地使用非智能選擇器和犯下的代碼上的錯誤。
更新:因為寫(xiě)了這篇文章,Topcoat.io 已經(jīng)使用<button>標簽來(lái)取代上面那個(gè)例子。這簡(jiǎn)直太棒了!然而,我對它們使用.is-disabled類(lèi)來(lái)指明這個(gè)按鈕是禁用的而忽略了disabled屬性持保留意見(jiàn)。你可以在評論區看到我和Topcoat 的代表在這方面的討論。對與促進(jìn)OOCSS 所帶來(lái)的WEB標準的災難,你可以在 semantic-ui.com中自行發(fā)現,它們示例中的“標準按鈕”居然是一個(gè)包含空的<i>標簽的<div>標簽。
看見(jiàn)是么就是什么
“如果它看起來(lái)像只鴨,游泳時(shí)也像只鴨,叫聲也像只鴨,那么它可能是一只鴨?!?/span>
一個(gè)裝飾得像按鈕一樣的鏈接,并且還能觸發(fā)像點(diǎn)擊按鈕那樣的Javascript 事件,對很多人來(lái)說(shuō),它是一個(gè)按鈕。然而,這只意味著(zhù)它已經(jīng)通過(guò)了前兩個(gè)階段的“鴨測試”。為了讓所有的用戶(hù)能夠運用歸納推理和辨別按鈕,它也***像這 樣。因為它仍然是一個(gè)鏈接,盡量避免這種不必要的混淆,因為這種輔助技術(shù)的使用者沒(méi)有追求一個(gè)語(yǔ)義但這又恰好是我們應當承擔的職責。
盡管如此,有些人還是堅持用a作為按鈕的標簽。超鏈接是比較容易完全重新地樣式化的一個(gè)元素。如果選擇a標簽作為元素,那么只有一個(gè)辦法讓它接近真正的按鈕。你猜對了:你***使用WAI ARIA role 屬性值來(lái)指明它的含義??梢?xún)H僅通過(guò)下列的屬性選擇器來(lái)確認一個(gè)超鏈接因為某些原因看起來(lái)像是一個(gè)按鈕。
1 [role="button"] {2 /* semantic CSS for modified elements that are announced as “button” in assistive technologies */3 }
質(zhì)量保證的屬性選擇器
“CSS給予了class 屬性強大的力量,作者可以基于那些沒(méi)有任何表現的元素(例如DIV和SPAN)在想象中設計他們的“文檔語(yǔ)言”,并通過(guò)class 屬性來(lái)賦予他們樣式信息。作者應該避免這種行為即使這種文檔語(yǔ)言的結構元素經(jīng)常得到大家認可和接受它們的意義?!?– “選擇器,” CSS Level 2, W3C
我們具有a和 button兩個(gè)元素的原因是為了在語(yǔ)義上劃分兩種完全不同的功能交互。超鏈接代表著(zhù)你將會(huì )去到的某個(gè)位置的符號,而按鈕是作為事件或者動(dòng)作的觸發(fā)源。一個(gè)是關(guān)于位置移動(dòng)的,另一個(gè)則是側重于轉換的。一個(gè)是促進(jìn)脫離的,另一個(gè)是促進(jìn)結合的。
為了確保我們不會(huì )做什么愚蠢的事情來(lái)讓我們的按鈕和超鏈接產(chǎn)生混淆。我們會(huì )創(chuàng )建一個(gè)使用智能屬性選擇器的CSS書(shū)簽并來(lái)測試兩個(gè)元素各自的有效性和質(zhì)量。
受到Eric Meyer的文章的一點(diǎn)啟發(fā)以及從DiagnostiCSS 中獲取了一些線(xiàn)索,這個(gè)樣式表會(huì )結合屬性選擇器和:not選擇器(或者非偽類(lèi)) 來(lái)在HTML 中把問(wèn)題高亮出來(lái)。與其他的兩種實(shí)現不同,它會(huì )使用偽元素來(lái)將錯誤打印到屏幕上。每一個(gè)錯誤都會(huì )采用漫畫(huà)字體以及粉紅色的背景來(lái)顯示。
通過(guò)把功能和表單連接起來(lái),我們可以看到丑陋的HTML 會(huì )間接地導致丑陋的 CSS。這是設計師濫用文檔帶來(lái)的后果。嘗試一下把revenge.css保存到你的CSS書(shū)簽中,并單擊這個(gè)書(shū)簽以在任何你喜歡的頁(yè)面觸發(fā)它。注意:它不會(huì )在服務(wù)在https協(xié)議上的頁(yè)面中起作用。
REVENGE.CSS
Drag to your bookmarks bar.
規則1
如果它是個(gè)超鏈接,那它就應該有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;
}
注意:在這個(gè)例子中我并不是要測試屬性的值,而是測試這個(gè)屬性是否有被設置,也就是說(shuō),[href]匹配的是任何含有href屬性的元素。這個(gè)測試 僅僅適用于超鏈接。這個(gè)測試可以這樣來(lái)理解,“對于每一個(gè)不具有href屬性的元素,為