簡介
CSS 偽類 (Pseudo-classes)是W3C里制定的一套選擇器的特殊狀態(tài),有幾十個之多淳地。語法如下:
selector:pseudo-class {property: value;}
我們比較常見的有:link
怖糊、:focus
、:active
等等颇象。今天我來介紹幾個比較有趣的偽類選擇器伍伤,并在某些場景里實現(xiàn)一些酷炫的功能。
:first-child
前段時間在開發(fā)一個dashboard的頁面遣钳,客戶提了一個需求扰魂,當dashboard頁面的todo為空時,顯示no task圖標。需求很簡單阅爽,有todo時隱藏圖標,沒todo顯示圖標荐开。
我看了一下組里小朋友的實現(xiàn)付翁,大體思路如下。很嫻熟地使用了v-if條件渲染晃听。
<section v-if="todos.length">
<h1>TODO</h1>
<ol>
<li v-for="todo in todos"> {{todo}}</li>
</ol>
</section>
<section v-else>
<v-icon>inbox</v-icon>
<p>No Task</p>
</section>
不過后來dashboard里需要增加與todo同級的news了百侧,然后代碼就變成了這樣:
<section v-if="todos.length+news.length">
<div v-if="todos.length">
<h1>TODO</h1>
...
</div>
<div v-if="news.length">
<h1>NEWS</h1>
...
</div>
</section>
<section v-else>
...
</section>
先不論代碼可讀性,<section v-if="...">
判斷語句會隨著新條目的增加不斷修改能扒,從開放閉合原則的角度來說,這并不是很適宜。
其實狰闪,這個案例里用一個簡單的CSS偽類:first-child
就可以很好的滿足需求永淌。如下,為圖標所在section添加一個no-task類见秤,并在樣式表里添加:first-child
選擇器砂竖。
<section v-if="todos.length">
...
</section>
<!-- 增加新的條目且不需要修改原先的代碼 -->
<section v-if="news.length">
...
</section>
<section class="no-task">
<v-icon>inbox</v-icon>
<p>No Task</p>
</section>
顧名思義,:first-child
用于選取屬于其父元素的首個子元素的指定選擇器鹃答。通俗來說乎澄,first-child指的是該元素本事為長子時的狀態(tài)。
樣式表內(nèi)容如下测摔。當no-task類為首元素時置济,顯示圖標,其他形態(tài)下隱藏自身锋八。
.no-task {
display: none;
}
.no-task:first-child {
display: block;
}
除此之外浙于,還有這么幾個類似功用的偽類,大家有興趣都可以去看一看:
- :last-child
- :first-of-type
- :last-of-type
- :nth-child
- :nth-last-child
CSS Counters
我發(fā)現(xiàn)很多同事學過CSS挟纱,但是知道CSS也能計數(shù)的并不多路媚。只要回想一下<ol>
標簽能產(chǎn)生從1~n的數(shù)值時,其實也不會覺得太奇怪了樊销。
CSS計數(shù)器的值通過使用
counter-reset
和counter-increment
操作整慎,在content
上應用counter()
或counters()
函數(shù)來顯示在頁面上。
再以上面todo為例加一個計數(shù)器围苫。
<section class="to-dos">
<h1>TODO</h1>
<ul>
<li class="to-do" v-for="item in todos"> {{item}}</li>
</ul>
<!-- counter of todos -->
<div class="counter"><div>
</section>
使用CSS計數(shù)器之前裤园,必須重置一個值(如:todo
),默認是0剂府。接著拧揽,每渲染一個 <li class='to-do'>
元素,todo計數(shù)+1。最后在.counter:after
的content
里顯示計數(shù)結果淤袜。(注意:content
只出現(xiàn)在html偽元素::before
或是::after
里)
section.to-dos {
counter-reset: todo; /* Set a counter named 'todo'*/
}
li.to-do {
counter-increment: todo; /* Increment 'todo' counter by 1 */
}
.counter:after {
content: counter(todo); /* Display the value of counter */
}
再稍微加工一下就可以實現(xiàn)如下功能了痒谴。請注意右上角的數(shù)字,這是利用CSS計數(shù)器動態(tài)生成的數(shù)值铡羡。
:checked and :not(checked)
我在瀏覽器default actions這一期里提到過用radio
做互斥按鈕积蔚。
這里就用到了input radio的:checked
偽類。那unchecked
呢烦周?沒有這個偽類尽爆,但是可以用否定偽類,:not(checked)
读慎。
回憶一下上述互斥按鈕的代碼:
<li v-for="item in items">
<span>{{item}}</span>
<label>
<input type="radio" name="radio" :value="item"/>
<div class="btn btn-primary selected">selected</div>
<div class="btn btn-light unselected">unselected</div>
</label>
</li>
列表項<li>
里的<input type="radio" name="radio">
共享同一個name漱贱,形成互斥效果。點擊<label>
后夭委,內(nèi)嵌的radio被置為:checked
幅狮,其他radio自動變?yōu)?code>:not(checked)。我們可以通過這個狀態(tài)差異來讓:checked
的.selected
兄弟可見株灸,.unselected
兄弟隱藏彪笼;反之,:not(checked)
的.unselected
兄弟可見蚂且,.selected
兄弟隱藏配猫。代碼實現(xiàn)如下。是的杏死,沒有用到一點Javascript泵肄。
input[type="radio"]:checked ~ .selected {
display: block;
}
input[type="radio"]:checked ~ .unselected {
display: none;
}
input[type="radio"]:not(checked) ~ .unselected {
display: block;
}
input[type="radio"]:not(checked) ~ .selected {
display: none;
}
checked, unchecked, and indeterminate.
突然想到了一個很冷的知識:radio和checkbox一共有三種狀態(tài) checked、 unchecked和indeterminate淑翼。沒錯腐巢,還有一個中間態(tài)。checkbox三態(tài)如下所示玄括。我記得早些年的QQ mail就利用過indeterminate
制作過一個特殊效果冯丙。
-
checkbox的
indeterminate
只能通過JS來設置let checkbox = document.getElementById("checkbox") checkbox.indeterminate = true;
radio的話,當所有同名radio都未被選擇時遭京,它們呈現(xiàn)的狀態(tài)叫
indeterminate
胃惜。
總結
CSS偽類是一個很有趣知識點,很多人覺得這個偽類太過奇技淫巧哪雕,甚至有嘩眾取寵之嫌船殉。其實CSS偽類,還有html的偽元素有許多實用的功能斯嚎,熟練掌握可以極大地簡化html利虫、減少JS的綁定挨厚。你的頁面也將更加簡潔優(yōu)雅。