虚拟类别选择器 ( 结构 )
虚拟类别选择器是根据“元素的状态”来选取元素,这篇教学会介绍透过元素在“文件结构”中的“位置”状态,进行选取元素的虚拟类别选择器,这类型的选择器有 :root、:empty、:first-child、:last-child、:nth-child(n)、:nth-last-child(n) 和 :only-child,都是非常方便实用的选择器。
教学影片
搭配教学影片一起阅读,效果会更好!欢迎大家订阅 STEAM 教育学习网的 Youtube 频道。
“结构位置”虚拟类别选择器
下方列出和“结构位置”有关的虚拟类别选择器 ( 支援度 All 表示主流浏览器都支援 ):
| 虚拟类别选择器 | 说明 | 支援度 |
|---|---|---|
| :root | 文件根元素,如果是 html 文件就是 html 元素。 | All |
| :empty | 元素里没有任何元素、字元或换行。 | All |
| :first-child | 同一层元素里的第一个元素。 | All |
| :last-child | 同一层元素里的最后一个元素 | All |
| :nth-child(n) | 同一层元素里,从头数来第 n 个元素。 | All |
| :nth-last-child(n) | 同一层元素里,倒数第 n 个元素。 | All |
| :only-child | 同一层只有自己一个元素。 | All |
:root
“:root”表示文件的“根元素”,在网页 HTML 文件里通常指的是“html”元素,但由于网页有时并非完全由 HTML 构成,有些时候会使用 XML 或 RSS,对应的根元素就会不相同,下方的 CSS 会让 html 元素的背景变成灰色。
:root {background: gray;}
:empty
“:empty”表示“空元素”,泛指“元素里没有任何元素、字元或换行”,有时透过程序自动产生的网页,或一些特殊需求的网页,会多出一些没有任何内容的元素,透过 :empty 选取这些元素后,搭配“display: none;”的样式,就能隐藏这些不应该存在的空元素,如此一来就不用特别透过 JavaScript 来清除这些元素。
:empty {display: none;}
除了隐藏空元素的功能,也可以透过样式的设定,替空元素加上特殊样式,例如下方的 CSS 会将所有的空元素加上灰色背景,但如果是“空的 div 元素”,就会变成红色背景。
<!-- HTML 程式碼 -->
<h2></h2>
<h3></h3>
<div></div>
<!-- CSS 程式碼 -->
<style>
* {width: 100px; height: 50px;} /* 所有元素的寬 100px 高 50px */
:empty {background: gray;} /* 所有空元素的背景灰色 */
div:empty {background: red;} /* 所有空元素是 div,背景紅色 */
</style>
:first-child
“:first-child”表示“同一层里的第一个元素”,下方的 CSS 会将 body 里,所有元素中的第一个子元素都变成红色文字,注意,如果直接写“* :first-child”,会造成 body 里的第一个元素也会变成红色。
<!-- HTML 程式碼 -->
<ul>
<li>apple</li> <!-- ul 裡第一個子元素 -->
<li>orange</li>
<li>banana</li>
</ul>
<div>
<h2>oxxo.studio</h2> <!-- div 裡的第一個子元素 -->
<h3>hello world!!</h3>
<span><em>Yes</em> or <em>No</em></span> <!-- 第一個 em 為 span 裡第一個子元素 -->
</div>
<!-- CSS 程式碼 -->
<style>
body * :first-child {color: red;} /* body 裡所有元素中的第一個子元素呈現紅色文字 */
</style>
除了单除使用 :first-child,如果在“开头加上元素名称”,就会表示“指定的元素的第一个”,以下方的 CSS 为例,就会单独将第一个 li 变色,而不会影响到其他的元素。
body * li:first-child {color: red;} /* body 裡所有元素中的第一個 li 呈現紅色文字 */
如果在“没有指定元素名称”的状况下使用 :first-child,需要注意浏览器在渲染网页时,会自动添加一些“隐藏元素”,例如 table 元素就有隐藏了一个 tbody 元素,如果单纯使用 table *:first-child,会发生内容元素全部套用样式的状况,因为 table 的第一个子元素是隐藏的 tbody,如果要解决这个问题,就需要明确定义元素名称。
<!-- HTML 程式碼 -->
<table border="1">
<tr>
<td>AAA</td><td>BBB</td>
</tr>
<tr>
<td>CCC</td><td>DDD</td>
</tr>
</table>
<!-- CSS 程式碼 -->
<style>
table :first-child {color: red;}
</style>
:last-child
“:last-child”表示“同一层里的最后一个元素”,下方的 CSS 会将 body 里,所有元素中的最后的子元素都变成红色文字,注意,如果直接写“* :last-child”,会造成 body 里的最后一个元素也会变成红色。
<!-- HTML 程式碼 -->
<ul>
<li>apple</li>
<li>orange</li>
<li>banana</li> <!-- ul 裡最後一個子元素 -->
</ul>
<div>
<h2>oxxo.studio</h2>
<h3>hello world!!</h3>
<span><em>Yes</em> or <em>No</em></span> <!-- div 裡的最後一個子元素 -->
</div>
<!-- CSS 程式碼 -->
<style>
body * :last-child {color: red;} /* body 裡所有元素中的最後一個子元素呈現紅色文字 */
</style>
除了单除使用 :last-child,如果在“开头加上元素名称”,就会表示“指定的元素的最后一个”,以下方的 CSS 为例,就会单独将最后一个 li 变色,而不会影响到其他的元素。
body * li:last-child {color: red;} /* body 裡所有元素中的最後一個 li 呈現紅色文字 */
:nth-child(n)
“:nth-child(n)”表示“同一层元素里,从头数来第 n 个元素”,下方的 CSS 会将 body 里,所有元素中从头数来的第二个子元素都变成红色文字。
<!-- HTML 程式碼 -->
<ul>
<li>apple</li>
<li>orange</li> <!-- ul 裡第二個子元素 -->
<li>banana</li>
<li>grape</li>
</ul>
<div>
<h2>oxxo.studio</h2>
<h3>hello world!!</h3> <!-- div 裡的第二個子元素 -->
<span><em>Yes</em> or <em>No</em></span> <!-- No 是 span 裡第二個子元素 -->
<a>Google</a>
</div>
<!-- CSS 程式碼 -->
<style>
body * :nth-child(2) {color: red;} /* body 裡所有元素中從頭數來的第二個子元素呈現紅色文字 */
</style>
除了单除使用 :nth-child(n),如果在“开头加上选择器”,就会表示“第二个且是特定元素”,以下方的 CSS 为例,就会单独将第二个 li 变色,而不会影响到其他的元素。
body * li:nth-child(2) {color: red;} /* body 裡所有元素中的第二個元素,而且是 li,呈現紅色文字 */
因为 :nth-child(n) 表示“第几个”,不论该元素是什么都会按照顺序选取,而搭配选择器则是“判断条件”,也就是要同时满足“几个”和“选择器”才会选取成功,此外要特别注意,<br> 换行符也属于第几个元素的选取范围,下方范例虽然设定了 div:nth-child(3),但因为第三个元素是 span 就不会被选取,又因为 span:nth-child(4) 第四个元素是 span 就会选取成功。
<!-- HTML 程式碼 -->
<div>div 1 ( 實際是 nth-child(1) )</div>
<div>div 2 ( 實際是 nth-child(2) )</div>
<span>span 1 ( 實際是 nth-child(3) )</span>
<span>span 2 ( 實際是 nth-child(4) )</span>
<br> ( 換行符號也算,實際是 nth-child(5) )
<div>div 3 ( 實際是 nth-child(6) )</div>
<div>div 4 ( 實際是 nth-child(7) )</div>
<span>span 3 ( 實際是 nth-child(8) )</span>
<div>div 5 ( 實際是 nth-child(9) )</div>
<div>div 6 ( 實際是 nth-child(10) )</div>
<!-- CSS 程式碼 -->
<style>
div:nth-child(1){color: red;}
div:nth-child(3){color: red;}
span:nth-child(4){color: red;}
div:nth-child(6){color: red;}
</style>
:nth-child(n) 里的 n 不仅可以只是数字,也可以使用奇数“odd”和偶数“even”这两个英文单字,使用后就会自动取得奇数项元素或偶数项元素。
<!-- HTML 程式碼 -->
<ul>
<li>apple</li>
<li>orange</li> <!-- 偶數變色 -->
<li>banana</li>
<li>grape</li> <!-- 偶數變色 -->
<li>papaya</li>
<li>coconut</li> <!-- 偶數變色 -->
</ul>
<ol>
<li>apple</li> <!-- 奇數變色 -->
<li>orange</li>
<li>banana</li> <!-- 奇數變色 -->
<li>grape</li>
<li>papaya</li> <!-- 奇數變色 -->
<li>coconut</li>
</ol>
<!-- CSS 程式碼 -->
<style>
ul li:nth-child(even) {color: red;} /* 偶數變色 */
ol li:nth-child(odd) {background: green;} /* 三的倍數變色 */
</style>
如果单纯使用 n,也可当作一个“根据 An+B 公式自动扩展的序列”( n 从 1 开始计算 ),例如“2n”就等于“2,4,6,8....”,又或者“2n+2”就是“4,6,8,10...”,例如下方的例子,ul 里偶数的 li 会是红色,ol 里的 li 则会使用三的倍数作为间隔变色。
<!-- HTML 程式碼 -->
<ul>
<li>apple</li>
<li>orange</li> <!-- 偶數變色 -->
<li>banana</li>
<li>grape</li> <!-- 偶數變色 -->
<li>papaya</li>
<li>coconut</li> <!-- 偶數變色 -->
</ul>
<ol>
<li>apple</li>
<li>orange</li>
<li>banana</li> <!-- 三的倍數變色 -->
<li>grape</li>
<li>papaya</li>
<li>coconut</li> <!-- 三的倍數變色 -->
</ol>
<!-- CSS 程式碼 -->
<style>
ul li:nth-child(2n) {color: red;} /* 偶數變色 */
ol li:nth-child(3n) {background: green;} /* 倒數奇數變色 */
</style>
:nth-last-child(n)
“:nth-child(n)”表示“同一层元素里,倒数第 n 个元素”,下方的 CSS 会将 body 里,所有元素中倒数第二个子元素都变成红色文字。
<!-- HTML 程式碼 -->
<ul>
<li>apple</li>
<li>orange</li>
<li>banana</li> <!-- ul 裡倒數第二個子元素 -->
<li>grape</li>
</ul>
<div>
<h2>oxxo.studio</h2>
<h3>hello world!!</h3>
<span><em>Yes</em> or <em>No</em></span> <!-- div 裡倒數第二個子元素 -->
<a>Google</a>
</div>
<!-- CSS 程式碼 -->
<style>
body * :nth-last-child(2) {color: red;} /* body 裡所有元素中從頭數來的第二個子元素呈現紅色文字 */
</style>
除了单除使用 :nth-last-child(n),如果在“开头加上选择器”,就会表示“倒数第二个,且是特定选择器”,以下方的 CSS 为例,就会单独将倒数第二个且是 li 的元素变色,而不会影响到其他的元素。
body * li:nth-last-child(2) {color: red;} /* body 裡所有元素中倒數第二個且是 li 呈現紅色文字 */
:nth-last-child(n) 里的 n 不仅可以只是数字,也可以使用奇数“odd”和偶数“even”这两个英文单字,使用后就会自动“倒数”取得奇数项元素或偶数项元素。
<!-- HTML 程式碼 -->
<ul>
<li>apple</li> <!-- 倒數偶數變色 -->
<li>orange</li>
<li>banana</li> <!-- 倒數偶數變色 -->
<li>grap</li>
<li>papaya</li> <!-- 倒數偶數變色 -->
<li>coconut</li>
</ul>
<ol>
<li>apple</li>
<li>orange</li> <!-- 倒數奇數變色 -->
<li>banana</li>
<li>grap</li> <!-- 倒數奇數變色 -->
<li>papaya</li>
<li>coconut</li> <!-- 倒數奇數變色 -->
</ol>
<!-- CSS 程式碼 -->
<style>
ul li:nth-last-child(even) {color: red;} /* 倒數偶數變色 */
ol li:nth-last-child(odd) {background: green;} /* 倒數奇數變色 */
</style>
如果单纯使用 n,也可当作一个会“根据 An + B 公式自动扩展的序列”( n 从 1 开始计算 ),例如“2n”就等于“...8,6,4,2”,又或者“2n+2”就是“...10,8,6,2”,例如下方的例子,ul 里倒数偶数的 li 会是红色,ol 里的 li 则会使用三的倍数作为倒数间隔变色。
<!-- HTML 程式碼 -->
<ul>
<li>apple</li> <!-- 倒數偶數變色 -->
<li>orange</li>
<li>banana</li> <!-- 倒數偶數變色 -->
<li>grape</li>
<li>papaya</li> <!-- 倒數偶數變色 -->
<li>coconut</li>
</ul>
<ol>
<li>apple</li> <!-- 倒數三的倍數變色 -->
<li>orange</li>
<li>banana</li>
<li>grap</li> <!-- 倒數三的倍數變色 -->
<li>papaya</li>
<li>coconut</li>
</ol>
<!-- CSS 程式碼 -->
<style>
ul li:nth-last-child(2n) {color: red;} /* 倒數偶數變色 */
ol li:nth-last-child(3n) {background: green;} /* 倒數三的倍數變色 */
</style>
:only-child
“:only-child”表示“同一层只有自己一个元素”,下方的 CSS 会将 body 里,所有元素中只有一个子元素的子元素变成红色文字。
<!-- HTML 程式碼 -->
<ul>
<li>apple</li>
<li>orange</li>
<li>banana</li>
<li>grape</li>
</ul>
<div>
<h2>OXXO.STUDIO</h2> <!-- 只有一個子元素,變色 -->
</div>
<div>
<h3>Hello World!!</h3> <!-- 只有一個子元素,變色 -->
</div>
<span><em>Yes</em> or <em>No</em></span>
<!-- CSS 程式碼 -->
<style>
body * :only-child {color: red;}
</style>
除了单除使用 :only-child,如果在“开头加上元素名称”,就会表示“子元素只有一个指定元素”,以下方的 CSS 为例,就会单独只有一个 h2 的 h2 变色,而不会影响到其他的元素。
body * h2:only-child {color: red;} /* body 裡所有元素中只有一個 h2 的 h2 變色 */
不过 :only-child 只针对有被标签包覆的“元素”有作用,如果父元素里有“纯文字”,因为没有被标签包覆的缘故,纯文字不属于元素,也就不会影响 :only-child 的判读,下方的范例中虽然 h3 后方有其他文字,但 h3 仍然会变色。
<!-- HTML 程式碼 -->
<ul>
<li>apple</li>
<li>orange</li>
<li>banana</li>
<li>grape</li>
</ul>
<div>
<h3>Hello World!!</h3> <!-- 只有一個子元素,變色 -->
我是純文字呦 <!-- 同一層裡有純文字 -->
</div>
<span><em>Yes</em> or <em>No</em></span>
<!-- CSS 程式碼 -->
<style>
body * :only-child {color: red;}
</style>
小结
CSS 和文件结构相关的虚拟类别选择器非常好用,不但可以根据结构快速选取元素,更可以协助减少许多 JavaScript 逻辑判断选取的功能,如果妥善运用,一定可以大幅简化 CSS 程序码,实现更好的排版方式与提升页面效能。
微信扫码关注
抖音扫码关注