1. 程式人生 > >CSS 屬性選擇器的深入挖掘

CSS 屬性選擇器的深入挖掘

CSS 屬性選擇器,可以通過已經存在的屬性名或屬性值匹配元素。

屬性選擇器是在 CSS2 中引入的並且在 CSS3 中得到了很好拓展。本文將會比較全面的介紹屬性選擇器,儘可能的去挖掘這個選擇器在不同場景下的不同用法。

 

簡單的語法介紹

  • [attr]:該選擇器選擇包含 attr 屬性的所有元素,不論 attr 的值為何。
  • [attr=val]:該選擇器僅選擇 attr 屬性被賦值為 val 的所有元素。
  • [attr~=val]:該選擇器僅選擇具有 attr 屬性的元素,而且要求 val 值是 attr 值包含的被空格分隔的取值列表裡中的一個。

子串值(Substring value)屬性選擇器,

下面幾個屬於 CSS3 新增語法,也被稱為“偽正則選擇器”,因為它們提供類似 regular expression 的靈活匹配方式。

  • [attr|=val] : 選擇attr屬性的值是 val 或值以 val- 開頭的元素(注意,這裡的 “-” 不是一個錯誤,這是用來處理語言編碼的)。
  • [attr^=val] : 選擇attr屬性的值以 val 開頭(包括 val)的元素。
  • [attr$=val] : 選擇attr屬性的值以 val 結尾(包括 val)的元素。
  • [attr*=val] : 選擇attr屬性的值中包含子字串 val 的元素(一個子字串就是一個字串的一部分而已,例如,”cat“ 是 字串 ”caterpillar“ 的子字串

 

CSS 屬性選擇器的最基本用法

屬性選擇器最基本的用法,就是通過元素的屬性值去選擇 DOM 元素。像這樣,將選中所有帶 href 屬性的DOM 元素:

[href] {
    color: red;
}

CodePen Demo -- 屬性選擇器基本用法

  

複雜一點點的用法

層疊選擇

div [href]{
...
}

多條件複合選擇

選擇一個 img 標籤,它含有 title 屬性,並且包含類名為 logo 的元素。

img[title][class~=logo]{
...
}

偽正則寫法

  • i 引數

忽略類名的大小寫限制,選擇包含 class 類名包含子字串為 text,Text,TeXt... 等情況的 p 元素。 這裡的 i 的含義就是正則裡面引數 i 的含義,ignore,忽略大小寫的意思。

p[class*="text" i] {
...
}

所以上面的選擇器可以選中類似這樣的目標元素:

<p class="text"></p>
<p class="nameText"></p>
<p class="desc textarea"></p>
  • g 引數

與正則表示式不一樣,引數 g 在這裡表示大小寫敏感(case-sensitively)。然而,這個屬性當前仍未納入標準,支援的瀏覽器不多。

CodePen Demo -- 屬性選擇器的偽正則用法 

 

配合 :not() 偽類

還有一種比較常用的場景就是搭配:not() 偽類,完成一些判斷檢測性的功能。譬如下面這個選擇器,就可以選取所有沒有 [href] 屬性的 a 標籤,新增一個紅色邊框。

a:not([href]){
    border: 1px solid red;
}

當然,複雜一點,我們可以搭配不僅僅一個 :not()偽類,像是這樣,可以同時多個配合使用,選擇一個 href, target, rel 屬性都沒有的 a 標籤:

a:not([href]):not([target]):not([rel]){
    border: 1px solid blue;
}

CodePen Demo -- 屬性選擇器配合 :not 偽類

 

重寫行內樣式?

甚至乎,如果有這種場景,我們還可以覆蓋掉行內樣式,像這樣:

<p style="height: 24px; color: red;">xxxxxx</p>

我們可以使用屬性選擇器強制覆蓋掉上述樣式:

[style*="color: red"] {
    color: blue !important;
}

 

組合拳用法,搭配偽元素提升使用者體驗

當然,屬性選擇器不一定只是單單的進行標籤的選擇。

配合上偽元素,我們可以實現很多有助提升使用者體驗的功能。

 

角標功能

這裡有一個小知識點,偽元素的 content 屬性,通過 attr(xxx),可以讀取到對應 DOM 元素標籤名為 xxx 的屬性的值。

所以,配合屬性選擇器,我們可以很容易的實現一些角標功能:

<div count=“5“>Message</div>
div {
    position: relative;
    width: 200px;
    height: 64px;
}

div::before {
    content: attr(count);
    ...
} 

 

這裡右上角的數字 5 提示角標,就是使用屬性選擇器配合偽元素實現,可以適應各種長度,以及中英文,能夠節省一些標籤。CodePen Demo -- 屬性選擇器實現角標功能

 

屬性選擇器配合偽元素實現類 title 功能

我們都知道,如果給一個圖片新增一個 title 屬性,當 hover 到圖片上面的時,會展示 title 屬性裡面附加的內容,類似這樣:

<img src="xxxxxxxxx" title="風景圖片">

這裡不一定是 img 標籤,其他標籤新增 title 屬性都能有類似的效果。但是這裡會有兩個問題:

  • 響應太慢,通常滑鼠 hover 上去要隔 1s 左右才會出現這個 title 框
  • 框體結構無法自定義,彈出框的樣式無法自定義

所以這裡,如果我們希望有一些自己能夠控制樣式的可快速響應的浮層,可以自定義一個類 title 屬性,我們把它稱作 popTitle,那麼可以這樣操作:

<p class="title" popTitle="文字彈出">這是一段描述性文字</p>
<p class="title" popTitle="標題A">這是一段描述性文字</p>
p[popTitle]:hover::before {
    content: attr(popTitle);
    position: absolute;
    color: red;
    border: 1px solid #000;
    ...
}

對比一下,第一個是原生自帶的 title 屬性,下面兩個是使用屬性選擇器配合偽元素模擬的提示: 

瀏覽器自帶的 title 屬性延遲響應是新增一層防抖保護,避免頻繁觸發,這裡也可以通過對偽元素新增一個100毫秒級的 transition-delay 實現延遲展示。

CodePen Demo -- 屬性選擇器配合偽元素實現類 title 功能

 

商品展示提示效果

好,上面的運用例項我們再拓展一下,考慮如何更好的運用到實際業務中,其實也是有很多用武之地的。譬如說,通過屬性選擇器給圖片新增標籤,類似一些電商網站會用到的一個效果。

我們希望給圖片新增一些標籤,在 hover 圖片的時候展示出來。

當然,CSS 中,諸如 <img> 、<input><iframe>,這幾個標籤是不支援偽元素的。

所以這裡我們輸出 DOM 的時候,給 img 的父元素帶上部分圖片描述標籤。通過 CSS 去控制這些標籤的展示:

<div class="g-wrap" desc1="商品描述AAA" desc2="商品描述BBB">
    <img src="https://xx.baidu.com/timg?xxx" >    
</div>
[desc1]::before,
[desc2]::after {
    position: absolute;
    opacity: 0;
}

[desc1]::before {
    content: attr(desc1);
}

[desc2]::after {
    content: attr(desc2);
}

[desc1]:hover::before,
[desc2]:hover::after{
    opacity: 1;
}

看看效果:

CodePen Demo -- 通過屬性選擇器給圖片新增標籤

 

屬性選擇器配合偽元素實現下載提示

我們知道,HTML5 對標籤新增了一個 download 屬性,此屬性指示瀏覽器下載 URL 而不是導航到它。

那麼,我們可以利用屬性選擇器對所有帶此類標籤的元素進行提示。像這樣:

<a href="https://www.xxx.com/logo.png" download="logo">logo</a>
[download] {
    position: relative;
    color: hotpink;
}

[download]:hover::before {
    content: "點選可下載此資源!";
    position: absolute;
    ...
}

當我們 hover 到這個連結的時候,就會這樣,提示使用者,這是一個可以下載的按鈕:

 

 

CodePen Demo -- 屬性選擇器配合偽元素做下載提示 

 

屬性選擇器配合偽元素對連結的協議進行提示(http/https)

現在大部分網站不是切了 https 就是走在切 https 的路上。如果頁面上的連結很多或者對跳轉頁面的協議有要求,使用屬性選擇器配合偽元素對連結的協議進行提示也不失為一種好方法。

a[href^="http:"]:hover::before {
    content: "這是一個http連結";
    ...
}

a[href^="https:"]:hover::before {
    content: "這是一個https連結";
}

CodePen Demo -- 屬性選擇器配合偽元素對連結的協議進行提示(http/https)

當然,偽元素的內容不一定是純文字的,為了給使用者更好的體驗,圖或者圖片加文字也是可以的。

譬如我們可以形象化地給 https 連結站點再加一個小綠鎖,符合使用者的一些常規認知。

這裡我將小綠鎖的圖片使用 base64 嵌入到偽元素當中,簡單的使用 text-indent 控制圖文的排布:

a[href^="https:"]:hover::before {
    content: "";
    padding-left: 16px;
    background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAb0lEQVQoz2NkQAJc5aIc//7962VgYIiDCi1iYmIq/tb5+gdMDROyBqhiGWYmJlVmJiZVBgYGGagYdsBRKvyZu1xUAsbnLheV4CgV/oxbQ4nwf0JiTAwkAkaIU4QaGf4z1uFX+b/pR/e7epJtGJEaAKDXHzEJ3KYmAAAAAElFTkSuQmCC");
    ...
}

這裡只是一個非常小的 Demo,實際情況是大部分使用者並不瞭解這個小綠鎖的含義,所以實際使用應該搭配文字輔助提示。

CodePen Demo -- 屬性選擇器配合偽元素對https協議進行圖文提示

 

屬性選擇器對檔案型別的處理

也可以對一些可下載資源進行視覺上 icon 的提示。

<ul>
    <li><a href="xxx.doc">Word File</a></li>
    <li><a href="xxx.ppt">PPT File</a></li>
    <li><a href="xxx.PDF">PDF File</a></li>
    <li><a href="xxx.MP3">MP3 File</a></li>
    <li><a href="xxx.avi">AVI File</a></li>
</ul>
a[href$=".doc" i]::before {
    content: "doc";
    background: #a9c4f5;
}
a[href$=".ppt" i]::before {
    content: "ppt";
    background: #f8e94f;
}
a[href$=".pdf" i]::before {
    content: "pdf";
    background: #fb807a;
}
a[href$=".mp3" i]::before {
    content: "mp3";
    background: #cb5cf5;
}
a[href$=".avi" i]::before {
    content: "avi";
    background: #5f8ffc;
}

CodePen Demo -- 屬性選擇器選擇檔名字尾

 

屬性選擇器對 input 型別的處理

屬性選擇器其實對 input 型別的元素是一個很好的幫手,因為 input 常用,且經常搭配很多不同功能的屬性值。

只不過,由於 input 型別無法新增偽元素。所以搭配屬性選擇器更多的通過屬性的各種狀態改變自身的樣式。

簡單舉個例子,譬如:

<input type="text">
<input type="text" disabled>

  

input[type=text][disabled] { 
    border: 1px solid #aaa;
    background: #ccc; 
}

這裡,我們選擇了 type=text 並且擁有 disabled 屬性的 input 元素,將它的背景色和邊框色設定為灰色。給與使用者更好的視覺提示。 

  

值得注意的點

注意選擇器優先順序 ,.class 與 [class=xxx] 是否等價

考慮這個問題,下面兩個選擇器是否等值?

<div class="header">
.header {
    color: red;
}

[class~="header"] {
    color: blue;
}

上述兩個選擇器,作用完全一致。然而,如果是下面這種情況,兩者就不一樣了:

<div id="header">
#header{
    color: red;
}

[id="header"] {
    color: blue;
}

這裡,ID 選擇器#header比屬性選擇器[id="header"]的權重更高,雖然兩者能夠選擇同樣的元素,但是兩者並不完全等價。

 

是否需要括號?

考慮下面三種情況,是否一致?

[class="header"]{ ... }

[class='header']{ ... }

[class=header]{ ... }

事實上,從 HTML2 開始,不新增括號的寫法就已經得到支援,所以上述三種寫法都是正確的。

然而,能夠不使用括號也是有限制的,再看看下面這種寫法:

a[href=bar] { ... }

a[href^=http://] {... }

第二個選擇器是個無效選擇器,:// 不括起來的話會識別錯誤,必須使用括號括起來像這樣a[href^="http://"],這裡具體的原因可以看看這篇文章:Unquoted attribute value validator。

所以保險起見,建議都加上括號。

 

CSS 語義化

編寫”具有語義的HTML”原則是現代、專業前端開發的一個基礎。當然,我們經常談論到的都是 HTML 語義化。

那麼,CSS 需要語義化嗎?CSS 有語義化嗎?例如上述的例子,使用特定的類名或者 id 選擇器皆可完成。那麼使用屬性選擇器的理由是什麼?

我的理解是,屬性(attribute)本身已經具有一定的語義,表達了元素的某些特徵或者功能,利用屬性選取元素再進行對該屬性值的特定操作,一定程度上也可以輔助提升程式碼的語義化。至少的提升了 CSS 程式碼的可讀性。但是 CSS 是否需要語義化這個問題就見仁見智了。

 

最後

 

這裡有幾篇文章還涵蓋了很多其他方面使用,可以對比觀看:

 

  • Semantic CSS With Intelligent Selectors
  • Splicing HTML’s DNA With CSS Attribute Selector

更多精彩 CSS 技術文章彙總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

好了,本文到此結束,希望對你有幫助 :)

如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告