本文为winter发布在极客时间的《重学前端》的学习笔记。
大家支持正版喔:time.geekbang.org/column/arti…
导语
选择器的基本意义是:根据一些特征,选中元素树上的一批元素。
选择器可以大致分为以下几类:
- 简单选择器:针对某一特征判断是否选中元素。
- 复合选择器:连续写在一起的简单选择器,针对元素自身特征选择单个元素,表示“且”的关系。
- 复杂选择器:由“(空格)”“ >”“ ~”“ +”“ ||”等符号连接的复合选择器,根据父元素或者前序元素检查单个元素。
- 选择器列表:由逗号分隔的复杂选择器,表示“或”的关系。
简单选择器
前四个都好理解,这里简单记录下属性选择器和伪类选择器。
属性选择器
- [att]:匹配具有某属性的标签,例如
[title]表示所有具有title属性的标签 - [att=val]:精确匹配,匹配属性中为某个值的标签,例如
[href="foo"]表示所有具体href属性,且属性值为foo的标签 - [att~=val]: 多种匹配,检查一个元素的值是否是若干值之一,这里的val不是一个单一的值了,可以是用空格分隔的一个序列。例如
[title~="flower"]可以匹配<img src="/i/eg_tulip.jpg" title="tulip flower" />。 - [att|=val]:开头匹配,检查一个元素的值是否是以val开头,这里的值必须是完整且唯一的单词,或者以
-分隔开,例如[title|="flower"]可以匹配<img src="/i/eg_tulip.jpg" title="flower tulip" />,但是不匹配<img src="/i/eg_tulip.jpg" title="tulip flower" />。 - [att*=val]:正则匹配,只要元素的值中存在val就行。例如
[title*="flower"]可以匹配<img src="/i/eg_tulip.jpg" title="aaaaaflowerbbbbb" />。 - [att^=val]:正则匹配,只要元素的值以val开头就行。例如
[title^="flower"]可以匹配<img src="/i/eg_tulip.jpg" title="flowerbbbbb" />。 - [att$=val]:正则匹配,只要元素的值以val结尾就行。例如
[title$="flower"]可以匹配<img src="/i/eg_tulip.jpg" title="aaaaaflower" />。
伪类选择器
伪类选择器是一系列由CSS规定好的选择器,它们以冒号开头。
伪类选择器有普通型和函数型两种,下面介绍主要使用的选择器,所有伪类选择器的汇总可以参考MDN。
树结构关系伪类选择器
- :root,伪类表示树的根元素。
对于 HTML 来说,:root表示 元素,除了优先级更高之外,与 html 选择器相同。但是随着scoped css和shadow root等场景出现,选择器可以针对某一子树来选择,这时候就很需要root伪类了。
声明全局CSS变量时,在:root中很有用:
:root {
--main-color: hotpink;
--pane-padding: 5px 42px;
}
- :empty,伪类表示没有子节点的元素,子节点只可以是元素节点或文本(包括空格)。
// html
<div class="box"><!-- I will be lime --></div>
<div class="box"></div>
<div class="box">I will be pink</div>
<div class="box"><span><span></div>
// css
.box:empty {
background: lime;
}
上面的例子中,.box:empty中仅前两个.box会生效。
- :nth-child 和 :nth-last-child
:nth-child(An+B)这个CSS伪类首先找到所有当前元素的兄弟元素,然后按照位置先后顺序从1开始排序,选择的结果为CSS伪类:nth-child括号中表达式(An+B)匹配到的元素集合(n=0,1,2,3...)。比如,3n+4匹配位置为 4、7、10、13...的元素。
此外,还可以使用:nth-child(odd)直接表示奇数位元素,等同于:nth-child(2n+1);可以用nth-child(2n)直接表示偶数位元素,等同于nth-child(2n)。
:nth-last-child的区别仅仅是从后往前数。
- :first-child 和 :last-child
也是查询所有当前元素的兄弟元素,但是分别表示第一个和最后一个元素。
- :only-child
匹配没有任何兄弟元素的元素
- :nth-of-type
是一个变形的语法糖,S:nth-of-type(An+B)是:nth-child(|An+B| of S)的另一种写法,仅使用兄弟元素中的S元素来进行排序查询。
<head>
<style>
p:nth-of-type(2n){
height:20px;
background:#ff0000;
}
</style>
</head>
<body>
<div>11111</div>
<p>22222</p>
<p>33333<span>44444</span></p>
<p><!-- I will be lime --></p>
<div>55555</div>
<p>66666</p>
</body>
效果如下:
以此类推,还有nth-last-of-type、first-of-type、last-of-type、only-of-type。详细可以参考MDN。
链接与行为伪类选择器
- any-link
表示任意的链接,包括有
href属性的a、area和link标签都可能匹配到这个伪类。
这是一个实验中的功能
此功能某些浏览器尚在开发中,请参考浏览器兼容性表格以得到在不同浏览器中适合使用的前缀。
- :link 表示未访问过的链接。
为了可以正确地渲染链接元素的样式,:link伪类选择器应当放在其他伪类选择器的前面,并且遵循LVHA的先后顺序,即::link — :visited — :hover — :active。
-
:visited 表示已经访问过的链接。
-
:hover 表示鼠标悬停在上的元素。
-
:active 表示用户正在激活这个元素,如用户按下按钮,鼠标还未抬起时,这个按钮就处于激活状态。
-
:focus 表示获得焦点的元素(如表单输入)。当用户点击或触摸元素或通过键盘的 “tab” 键选择它时会被触发。
-
:focus-within 表示一个元素获得焦点,或,该元素的后代元素获得焦点。换句话说,元素自身或者它的某个后代匹配
:focus伪类。
在Selector Level 4中提出,需要注意兼容性问题。
- :target 用于选中浏览器URL的hash部分所指示的元素,该元素的id与当前URL片段匹配。
// css
:target {
border: 2px solid black;
}
// url
http://www.example.com/index.html#section2
在上述场景中,:target可以匹配下面的元素(id为section2):
<section id="section2">Example</section>
-
:checked 表示任何处于选中状态的
radio(),checkbox() 或select元素中的option元素。 -
:disabled 和 :enabled 表示任何被禁用的元素。如果一个元素不能被激活(如选择、点击或接受文本输入)或获取焦点,则该元素处于被禁用状态。与之相对的,元素有一个启用状态,可以使用
:enabled来选择。
逻辑伪类选择器
- :not 用来匹配不符合一组选择器的元素。由于它的作用是防止特定的元素被选中,它也被称为反选伪类(negation pseudo-class)。
/* 选择所有不是段落(p)的元素 */
:not(p) {
color: blue;
}
注意:
- :not() 伪类不能被嵌套,这意味着 :not(:not(...)) 是无效的。
- 由于伪元素不是简单的选择器,他们不能被当作 :not() 中的参数,形如 :not(p::before) 这样的选择器将不会工作。
- 可以利用这个伪类提高规则的优先级。例如,
#foo:not(#bar)和#foo会匹配相同的元素,但是前者的优先级更高。- :not(.foo) 将匹配任何非 .foo 的元素,包括 和 。
- 这个选择器只会应用在一个元素上,无法用它来排除所有父元素。比如,
body :not(table) a依旧会应用到表格元素<table>内部的<a>上, 因为<tr>将会被:not(table)这部分选择器匹配。
在选择器4级标准,则允许:not接受一个选择器列表,这意味着选择器支持嵌套,仅靠:not即可完成选择器的一阶真值逻辑完备,但目前还没有看到浏览器实现它。
其它伪类选择器
还有一些草案中或者不常用的选择器,需要大概了解即可。
-
国际化:用于处理国际化和多语言问题
-
音频/视频:用于区分音视频播放状态
- play
- pause
-
时序:用于配合读屏软件等时序性客户端的伪类
- current
- past
- future
-
表格:用于处理table的列的伪类
- nth-col
- nth-last-col
复杂选择器
在CSS规则中,选择器部分是一个选择器列表。
根据选择器列表的语法,我们可以将选择器的连接方式可以理解为像四则运算一样有优先级:
- 第一优先级(复合选择器)
- 无连接符号
- 第二优先级(复杂选择器)
- “空格”
- “~”
- “+”
- “>”
- “||”
- 第三优先级(选择器列表)
- “,”
复杂选择器是针对节点关系的选择,下面简单描述下使用的连接符号:
- 空格:查找后代,表示选中所有符合条件的后代节点。
- >:子代,表示选中符合条件的子节点。
- ~: 后继,表示选中所有符合条件的后继节点,后继节点即跟当前节点具有同一个父元素,并出现在它之后的节点
- +: 直接后继,表示选中符合条件的直接后继节点,直接后继节点即nextSlibling
- ||: 列选择器,表示选中对应列中符合条件的单元格
<head>
<style>
.p1 span{
color:#ff0000;
}
.p2>span {
color:#ff0000;
}
.p3~p {
color:#ff0000;
}
.p3+p {
color: blue;
}
</style>
</head>
<body>
<p class="p1">p1:<span>这是子节点信息<span>这是后代信息</span></span></p>
<p class="p2">p2:<span>这是子节点信息<p>这是后代信息</p></span></p>
<p class="p3">p3:</p>
<p class="p4">p4</p>
<p class="p5">p5</p>
</body>
效果如下:
针对||选择器的示例可以参考这里。
选择器的优先级
CSS标准用一个三元组 (a, b, c) 来构成一个复杂选择器的优先级。
- id选择器的数目记为a;
- 伪类选择器和class选择器、属性选择器的数目记为b;
- 伪元素选择器和标签选择器数目记为c(伪元素见下文);
- “*” 不影响优先级。
CSS标准建议用一个足够大的进制,获取“ a-b-c ”来表示选择器优先级。
specificity = base * base * a + base * b + c
这里有几个点需求注意:
- 同一优先级的选择器遵循“后面的覆盖前面的”原则
- 选择器的优先级是针对复杂选择器的优先级,选择器列表不会合并计算优先级
- 行内属性的优先级永远高于CSS规则
- 在选择器前加上“!import”,会高于行内属性的优先级
伪元素
伪元素是一种重要的简单选择器,也是一种机制。伪元素的语法跟伪类相似,但是实际产生的效果却是把不存在的元素硬选出来。
下面是一些兼容性可用的伪元素,所有的伪元素列表可以参考MDN。
- ::first-line
选中块级元素的第一行元素。这里的第一行,指的是排版后显示的第一行,取决于很多因素,包括元素宽度,文档宽度和文本的文字大小,跟HTML代码中的换行无关。
::first-line伪元素只能在块容器中,所以,::first-line伪元素只能在一个display值为block,inline-block,table-cell或者table-caption中有用。在其他的类型中,::first-line是不起作用的。
CSS标准规定了::first-line必须出现在最内层的块级元素之内。在下面的情况中,由于第一行是span元素,::first-line是不生效的。
<div>
<span id=a>First paragraph</span><br/>
<span>Second paragraph</span>
</div>
// css
div::first-line {
color:blue;
}
此外,CSS标准只要求::first-line实现有限的几个CSS属性,都是文本相关(详细信息可以参考这里)。
- ::first-letter
选中某块级元素第一行的第一个字母,并且文字所处的行之前没有其他内容(如图片和内联的表格)。
首行只在
block-container box内部才有意义, 因此::first-letter只在display属性值为block,inline-block,table-cell,list-item或者table-caption的元素上才起作用。其他情况下,::first-letter毫无意义。
和::first-line不同,::first-letter能出现在span内。
<div>
<span id=a>First paragraph</span><br/>
<span>Second paragraph</span>
</div>
// css
div::first-letter {
color:blue;
}
这种情况下,首行的第一个字母能正常显示蓝色。
此外,CSS标准只要求::first-letter实现有限的几个CSS属性,都是文本相关(详细信息可以参考这里)。
- ::before 和 ::after
和上面两种伪元素不同,
::before表示在元素内容之前插入一个虚拟的元素,::after则表示在元素内容之后插入,都是创造出一个新的元素。
这两种伪元素,通常会配合content属性来为该元素添加装饰内容。
<p class="special">I'm real element</p>
.special::before {
display: block;
content: "pseudo! ";
}
::before和::after还支持content为counter。
<p class="special">I'm real element</p>
.special::before {
display: block;
content: counter(chapno, upper-roman) ". ";
}
配合clear属性,也可以用于清除浮动。
.clear:after{
content:"";
display: block;
clear: both;
}
总结
选择器可以大致分为四类:简单选择器、复合选择器、复杂选择器、选择器列表。
使用复合选择器、复杂选择器、选择器列表时,选择器的连接方式像四则运算一样有优先级。
伪元素也作为一种简单选择器,有其独有的机制,实际产生的效果是把不存在的元素硬选出来。