當看到 CSS Selectors Level 4 很多人會理所當然地喊出 CSS4。但是,這里必須明確一個概念,目前所謂的 CSS3 和 CSS4 都是 CSS2.1 以后對某一些 CSS 模塊進行升級更新后的稱呼。CSS3 和 CSS4 永遠都不會出現,它們只是為了區分 CSS 模塊升級后的等級,例如有些 CSS 選擇器在之前就存在了,但是此時我們為它添加了新的特性,那么這個模塊就升級到了 CSS Selectors Level 3 中,如果再一次升級,那么就變成了 CSS Selectors Level 4。下面我們可以對目前 W3C 工作草案中的 CSS Selectors Level 4 新特性進行一個階段性總結,之所以叫階段性,是因為未來可能有更多的新特性加入。
:not() 用于將符合規則的元素剔除,將樣式規則應用于其他元素上。在 CSS3 中已經有 :not(),不過在 CSS3 中只能使用簡單的匹配規則,例如 :not(p) 用來選擇不是 <p></p> 的元素。而在 CSS4 中,可以應用更復雜的匹配規則,但是同樣地不允許嵌套使用,例如 :not(:not(...))。
.negation { color: black; } .negation .default:not([data-red="no"]) { color: red; } .negation .default a { color: green; } .negation .default a:not([rel="green"], [rel="default"]) { color: blue; }
<div class="negation"> <div class="default" data-red="no"> <a href="http://www.baidu.com" rel="green">這里是綠色</a> <a href="http://www.ele.me" rel="default">這里也是綠色</a> <a href="http://www.sina.com" rel="blue">這里是藍色</a> </div> <div class="default" data-red="no"> 這里是黑色 </div> <div class="default" data-red="yes"> 這里是紅色 </div> </div>
:not() 小提示
我們可以利用 :not() 來對 CSS 樣式進行一個優先級提升,例如 div:not(span) {…} 跟 div {…} 是同個概念,但是明顯地前者的優先級更高。
想解鎖更多
:not()的使用姿勢就去看 The Negation Pseudo-class 草案。
:matches() 用于匹配所述規則的元素,并應用相應的樣式規則,同樣不允許嵌套使用,-webkit-any() 和 -moz-any() 是它的兩個兼容性寫法。它可以讓我們節省書寫大量的 CSS 樣式匹配規則,讓我們從大量重復的規則書寫中解放出來。
.matches { color: black; } .matches :matches(span, div) :matches(span, div) { color: green; } /*
等同于
.matches span div,
.matches span span,
.matches div span,
.matches div div {
color: green;
}
*/ .matches :-webkit-any(span, div) :-webkit-any(span, div) { color: green; } .matches :-moz-any(span, div) :-moz-any(span, div) { color: green; } .matches :matches(.a, .b) :matches(.a, .b) { color: red; } /*
等同于
.matches .a .a,
.matches .a .b,
.matches .b .a,
.matches .b .b {
color: red;
}
*/ .matches :-webkit-any(.a, .b) :-webkit-any(.a, .b) { color: red; } .matches :-moz-any(.a, .b) :-moz-any(.a, .b) { color: red; }
<div class="matches"> <span> <div>綠色</div> </span> <span> <span>綠色</span> </span> <div> <span>綠色</span> </div> <div> <div>綠色</div> </div> <div class="a"> <div class="b">紅色</div> </div> <div class="b"> <div class="a">紅色</div> </div> <div class="a"> <div class="a">紅色</div> </div> <div class="b"> <div class="b">紅色</div> </div> </div>
Case-Sensitivity 用于聲明某個匹配規則中,對字符串或者某個 value 的匹配不區分大小寫。該標志聲明于 ] 即右中括號之前,例如 [data-value="case" i],其中的 i 就是 Case-Sensitivity 標識。但是如果我們需要明確區分大小寫區別的時候,該標識可能會導致某些不可意料的后果,所以使不使用該標識應該明確使用的場景是否對數據來源的大小寫敏感。
.case-sensitivity :matches([data-value="case" i]) { color: yellow; }
<div class="case-sensitivity"> <p data-value='Case'>Case</p> <p data-value="case">case</p> </div>
以上的例子,data-value 雖然既有大寫也有小寫,但是由于我們聲明了 Case-Sensitivity,所以無論大小寫都會被匹配。像例子中 case,Case,CASE 等都會被匹配。
:dir() 用于匹配符合某個方向性的元素,例如 :dir(ltr) 和 dir(rtl)。顧名思義,ltr 表示 left to right,即方向從左到右,rtl 表示 right-to-left,即方向從右到左。值得注意的是,使用 :dir() 匹配元素和使用 [dir=...] 在某個程度上是一樣的效果,但是一個區別是 [dir=...] 無法匹配到沒有顯示聲明 dir 的元素,但是 :dir() 卻可以匹配到由瀏覽器計算得到或者繼承來的 dir 屬性的元素,詳情可以看一下草案。因此,如果我們有明確地對某個元素聲明 dir,那我們大可以使用 [dir=...] 的形式來匹配某個元素,但是如果我們只是單純從父元素繼承而來的 dir,那么此時還是需要用到:dir()。
.dir :dir(ltr) { color: blue; } .dir :dir(rtl) { color: green; }
<div class="dir"> <p dir="ltr">從左到右</p> <p dir="rtl">從右到左</p> </div>
:lang() 用于匹配聲明了 lang=value 的元素,并且可以使用通配符匹配,例如 p:lang(*-CH) 將可以匹配 de-CH 的 p 元素。
.lang p:lang(de-DE) { color: green; } .lang p:lang(*-CH) { color: blue; }
<div class="lang"> <p lang="de-DE-1996">de-DE-1996</p> <p lang="de-CH">de-CH</p> </div>
:any-link 用于匹配帶有 href 屬性的超鏈接元素,例如 <a>,<area>,<link> 等帶有 href 屬性的元素。:-webkit-any-link 和 :-moz-any-link 是它的兼容性寫法。目前工作組對該選擇器的命名尚不滿意,未來該選擇器可能會修改其名字。該選擇器的作用在于可以選出所有帶有鏈接的元素,如果使用舊方法,那么只能使用標簽名的方式或者a[href=value] 的方式去匹配。
.link a:any-link { color: red; } .link a:-webkit-any-link { color: red; } .link a:-moz-any-link { color: red; }
<div class="link"> <a href="#">我是帶有顏色的超鏈接</a> </div>
:scope 用于匹配當前作用域下的頂級元素。但是目前 <style scoped> 已經被移除——issue,所以 :scope 基本等效于:root。
<div class="scope"> <p>This paragraph is outside the scope.</p> <div> <style scoped> :scope { background-color: red; } p { color: blue; } </style> <p>This paragraph is inside the scope.</p> </div> </div>
以上代碼,第二個 div 將會有紅色背景,并且他的所有 <p> 子元素都將擁有藍色文字。
我個人用 時間軸偽類 統一稱呼 :current(), :past(), :future() 這三個偽類。:current() 匹配時間軸當前的元素,:past() 匹配 :current()元素之前的元素,:future() 則匹配當前時間軸后的所有元素。這里說的時間軸指的是例如WebVTT。值得注意的是,規范中寫道如果使用的時間軸并不是文檔語言所規定的,那么 :past() 和 :future() 有可能分別匹配 :current() 元素的前面的兄弟元素和后面的兄弟元素。由于在 Chrome Canary 和 Safari TP 上都不支持這幾個偽類,所以無法實驗正確性。下面使用的例子是從這個網址摘過來的。
:current(p, span) { background-color: yellow; } :past(p, span), :future(p, span) { background-color: gray; }
<video controls preload="metadata"> <source src="http://html5demos.com/assets/dizzy.mp4" type="video/mp4" /> <source src="http://html5demos.com/assets/dizzy.webm" type="video/webm" /> <source src="http://html5demos.com/assets/dizzy.ogv" type="video/ogv" /> <track label="English" kind="subtitles" srclang="en" src="http://www.iandevlin.com/html5test/webvtt/upc-video-subtitles-en.vtt" default> </video>
在 radio 和 checkbox 元素上一般有兩種狀態——選中 和 未選中,但是有的時候的狀態會是不確定狀態,而:indeterminate 就是匹配這種不確定狀態的 radio 或 checkbox。
:indeterminate + label { background-color: gray; }
<input type="radio" name="name" id="test"> <label for="test">未確定狀態</label>
通常地,radio 和 checkbox 在沒有聲明選中狀態時,默認只有兩種可能性:checked 和 unchecked,為了讓他們出現第三種狀態,我們可以借助 JS 來控制:
document.querySelector('#test').indeterminate = true;
上面例子的 <label> 在 <input> 處于 indeterminate state 的時候,文字將會變為灰色。
:default 匹配一組相似元素集合中的默認元素,例如 <form> 中有多個 <input>,其中有一個是 <input type="submit">,那么該元素將會被匹配。此外還有 <option> 也有默認元素。
.default .default-form :default { background-color: gray; }
<div class="default"> <form class="default-form" action="#" method="get"> <input type="submit" name="name" value="submit"> <input type="reset" name="name" value="reset"> </form> </div>
在 <input type="email"> 中,如果我們輸入了 abc123,那么此時 :invalid 將會匹配該元素,假如我們輸入abc123@163.com,那么此時 :valid 將會匹配該元素。這里要注意假如我們沒有為 <input> 作約束,例如<input type="text">,那么它的任意輸入將使元素既不會被 :valid 匹配,也不會被 :invalid 匹配。
.valid input:valid { color: green; } .valid input:invalid { color: red; }
<div class="valid"> <input type="email" name="eamil_valid" value="abc@abc.com"> <input type="email" name="email_invalid" value="abc"> </div>
:in-range 和 :out-of-range 只對有被條件約束的元素起作用,例如 <input type="number" min="1" value="1">,如果輸入數字小于 1,那么將會被 :out-of-range 匹配,反之則是被 :in-range 匹配。在很多時候,我們需要對“臟值”做一個高亮的顯示,以前可能需要配合 JS 對值的邊界進行檢測,然后在對元素的樣式進行修改。而現在,有了這兩個偽類的存在,我們可以完全使用 CSS 來控制。
.range input:in-range { color: green; } .range input:out-of-range { color: red; }
<div class="range"> <input type="number" name="range" value="1" min="1" max="10"> </div>
:required 和 :optional 分別匹配帶有 required 標識的元素和不帶 required 標識的元素。同樣地,我們可以利用這兩個偽類來對需要填寫的元素添加特定的樣式。
.optionality input:required { color: green; } .optionality input:optional { color: red; }
<div class="optionality"> <input type="text" name="required" value="required" required> <input type="text" name="optional" value="optional"> </div>
:user-error 會匹配 :invalid, :out-of-range 和沒有任何值的 :required 元素,但是假如是初始化時就觸發這三種錯誤,user-error 將不會匹配該元素,只有當用戶和元素進行交互或者提交了該表單并且觸發了這三種錯誤,:user-error 才會被觸發。Chrome 和 Safari 可能尚未支持,所以無法驗證正確性。
.user-error input:user-error { color: red; } .user-error input:valid { color: green; }
<div class="user-error"> <input type="email" name="eamil_valid" value="abc@abc.com"> <input type="email" name="email_invalid" value="abc"> </div>
:read-only 匹配不可被編輯的元素,:read-write 則匹配可被編輯的元素,例如 <input> 或者 contenteditable="true"的元素。:-moz-read-only 和 :-moz-read-write 分別是他們的兼容性寫法。
.mutability :read-only { color: red; } .mutability :read-write { color: green; }
<div class="mutability"> <input type="text" name="read-write-input" value="read-write"> <p contenteditable="true">read-write-paragraph</p> <p>read-only-paragraph</p> </div>
:placeholder-shown 匹配 placeholder 文字顯示時的 <input> 元素。::-webkit-input-placeholder,::-moz-placeholder, :-ms-input-placeholder 分別是它在不同瀏覽器的兼容性寫法。在此之前,原生的 placeholder 文字是沒有方法去改變其顏色的,大多數做法是使用 value 來代替 placeholder,同時利用 JS 對 input 的 focus 事件進行監聽,將 value 清空,從而達到一個模仿 placeholder 的效果。
.placeholder input:placeholder-shown { color: green; } .placeholder input::-webkit-input-placeholder { color: green; } .placeholder input::-moz-placeholder { color: green; } .placeholder input:-ms-input-placeholder { color: green; }
<div class="placeholder"> <input type="text" name="placeholder" placeholder="placeholder is green"> </div>
該特性將對例如 <table> 的柵格布局起作用。它包含 :column(selector), :nth-column(n) 和 :nth-last-column(n)。目前瀏覽器都還未支持,無法實驗正確性。這些偽類將讓柵格布局的樣式控制變得更為簡單,不過更多的試驗要等到瀏覽器支持才能一一試驗。
:column(selector) 將匹配例如 <table> 中 帶有 selector 類名的那一列的所有元素。
:column(.selected) { color: green; }
<table> <col class="selected" /> <col class="blur" /> <col class="blur" /> <tr> <td>A</td> <td>B</td> <td>C</td> </tr> <tr> <td>D</td> <td>E</td> <td>F</td> </tr> <tr> <td>G</td> <td>H</td> <td>I</td> </tr> </table>
在上面的例子中,A、D、G 都將是綠色的。
:nth-column(n) 匹配括號內 n 的計算值的某一列的元素,計算方式是從頭開始計算,而 :nth-last-column(n) 則是從后開始計算。
:nth-column(2n) { color: red; } :nth-last-column(3n) { color: green; }
<table> <col class="selected" /> <col class="blur" /> <col class="blur" /> <tr> <td>A</td> <td>B</td> <td>C</td> </tr> <tr> <td>D</td> <td>E</td> <td>F</td> </tr> <tr> <td>G</td> <td>H</td> <td>I</td> </tr> </table>
Tree-Structural pseudo-classes 是 CSS3 中的規范,但在 CSS Selectors Level 4 中加入了 :blank,它和 :empty 類似,區別在于 :empty 只能匹配沒有任何內容的元素,而 :blank 可以匹配帶有 spaces(空格), tabs(縮進符) 和segment breaks(段落過段) 內容的元素。
>>
A >> B 匹配祖先元素為 A 的 B元素,其用法與 A B 一樣,與 >, +, ~ 用意一樣,不過意義不同。
上面的特性都已經存在 Working Draft 中,還有一些 Editor’s Draft 的特性,也順帶一提。
:has(selector) 匹配含有 某些規則 的元素。
下面例子將匹配含有 img 子元素的 a 元素:
a:has(> img)
/* 將匹配擁有 dt 兄弟元素的 dt 元素 */ dt:has(+ dt)
下面例子將匹配不含有 h1、h2、h3、h4、h5、h6 元素的 section 元素:
section:not(:has(h1, h2, h3, h4, h5, h6))
和上面例子不同,下面交換了兩個偽類的嵌套,表示匹配含有的不是 h1、h2、h3、h4、h5、h6 子元素的元素,區別在于這種寫法要求必須含有一個子元素,而上面的寫法可以不含有子元素也會被匹配:
section:has(:not(h1, h2, h3, h4, h5, h6))
:drop 和 :drop() 匹配可被放置拖動元素的目標元素,兩者區別在于 :drop() 可以匹配一些規則,包括 active, valid,invalid。active 會匹配可被放置的目標元素,valid 匹配放置的元素為合法元素的目標元素,invalid 反之。如果:drop() 括號里沒有任何過濾,那么將和 :drop 沒有區別。
文章介紹了目前 CSS Selectors Level 4 的一些新的特性,我們看到 CSS 正在逐漸將以前需要依賴 JS 做到的事情轉化為 CSS 自身能夠處理的過程,這個將大大降低了 CSS 和 JS 之間的代碼耦合,從而也降低了項目迭代過程中的維護成本。從 1996 年發表的 CSS1 規范至今已經過去了 20年,從瀏覽器廠商的各自為戰到現在各個瀏覽器廠商遵守規范進行 CSS 新特性的開發,可以說現在前端因為瀏覽器兼容性的原因所造成的開發成本已經不如以前了,當然,現在還存在許多需要與 IE8+ 打交道的網站,但是這個比例已經大大降低了。還有新的挑戰來源于手機端 Web 的興起,手機的性能遠遠不及 PC 的性能,而國內手機瀏覽器內核的百花齊放又再一次讓兼容性這個嚴峻的問題擺在了前端開發者眼前,開發者們可以在開源社區中尋找各種 polyfill 來消除這種差異,也可以利用各種 CSS hack 來解決不同瀏覽器的兼容性,但是不可避免地會對性能造成影響。
其實說到了 CSS,不得不說與 CSS 密不可分的 JavaScript,JavaScript 自從 ES6 的發表,解決了 JavaScript 某些方面多年來混亂的局面,EcmaScript 的版本更新頻率也變得勤快了起來。在 ES6 中我們可以看到的是其解決很多 ES5 上存在的問題,例如異步事件處理,其新增了許多方法我們都發現 JQuery、underscore 等知名庫的影子,所以說,開發者的熱情是推動規范的不可或缺的中堅力量。規范的制定不再是一言堂,開發者們也有了說話和建議的余地。
無論如何,相信在各大廠商的和 W3C 工作組的推動下,未來不管在 CSS 還是 JavaScript 上,將會逐漸走向規范上的統一,讓我們拭目以待吧!
本站文章版權歸原作者及原出處所有 。內容為作者個人觀點, 并不代表本站贊同其觀點和對其真實性負責,本站只提供參考并不構成任何投資及應用建議。本站是一個個人學習交流的平臺,網站上部分文章為轉載,并不用于任何商業目的,我們已經盡可能的對作者和來源進行了通告,但是能力有限或疏忽,造成漏登,請及時聯系我們,我們將根據著作權人的要求,立即更正或者刪除有關內容。本站擁有對此聲明的最終解釋權。