css选择器
css选择器用来选中DOM元素。
其实css选择器是一种表达式,其被浏览器解析用来选中符合规则的DOM节点。我们在介绍表达式的时候曾经提到包但是有简单和复杂之分,而复杂表达式则是由简单表达式构成的。
css选择器也有简单和复杂之分,和普通的编程语言中的用于计算的表达式不同的是,css选择器的层级可以分为4级,它们从小到大分别是:
- 简单选择器
- 复合选择器
- 复杂选择器
- 选择器列表
和表达式相同的是,构成选择器的最基本的元素就是简单选择器
,而且简单选择器关乎一个选择器权重的计算,所以我们对css选择器的介绍自然就是从简单选择器开始的。
简单选择器
简单选择器是针对元素的某个特征来进行选择的,css中的简单选择器一共有以下几种:
-
ID选择器
顾名思义,ID选择器就是根据元素的id属性来选择元素,id选择器在书写的时候需要以
#
开头,如下:#app { attr: value; }
-
元素选择器
元素选择器是使用html标签名称进行元素的选择的,如下
a { attr: value; }
上述的示例代码中,a是一个元素(标签)的名字,这是一个a标签
-
伪元素选择器
伪元素之所以被称为伪元素,意思就是我们在编写HTML文档的时候,并不包含这样的元素,伪元素只是代表了一个真实存在的元素的一个位置,这让我们可以针对这个位置来实现一些样式的定制或者是实现一些有用的功能。
目前来说,兼容性达到可用的伪元素有如下几个:
-
::first-line
表示元素的第一行
-
::first-letter
表示元素的第一个字母
-
::before
表示元素前面的位置
-
::after
表示元素后面的位置
在实际的开发中,我们最常用的伪元素可能就是
::before
了,比如我们可以使用这个伪元素来自动为一篇文章的标题插入序号(本站文章标题的序号就是这么实现的)。伪元素选择器在书写的时候需要使用
::
开头并且书写浏览器承认的伪元素,如下:h1::before { content: 'h1'; display: inline-block; }
需要特别注意的是,css标准中规定,必须为::before或者是::after伪元素指定content属性其才会被渲染。
-
-
类选择器
类选择器根据元素的属性 class来选中元素,其能够识别以空格分隔的class列表的语法,类选择器是我们用的最多的一种选择器,如下:
.app { attr: value; }
-
伪类选择器
伪类和伪元素类似,我们在编写文档的时候并不会为某个元素加上一个class,伪类其实代表的是元素的一种状态,比如伪类可以代表在某个元素上是不是发生了某个事件(比如鼠标悬停)、可以代表树结构关系(元素在DOM中的位置状态)、甚至还可以代表一种函数的调用,比如
:not()
就代表反选。根据作用的不同,伪类选择器一般可以分为树结构关系伪类、链接伪类、行为伪类和逻辑伪类。
树结构关系伪类选择器
-
:root 伪类表示树的根元素
在选择器是针对完整的 HTML 文档情况,我们一般用 HTML 标签即可选中根元素。但是随着 scoped css 和 shadow root 等场景出现,选择器可以针对某一子树来选择,这时候就很需要 root 伪类了。
-
:empty 伪类表示没有子节点的元素
这里有个例外就是子节点为空白文本节点的情况。
-
:nth-child 和 :nth-last-child 这是两个函数型的伪类,CSS 的 An+B 语法设计的是比较复杂的,我们这里仅仅介绍基本用法。我们还是看几个例子:
-
:nth-last-child 的区别仅仅是从后往前数。
-
:first-child :last-child 分别表示第一个和最后一个元素。
-
:only-child 按字面意思理解即可,选中唯一一个子元素。
of-type 系列,是一个变形的语法糖,S:nth-of-type(An+B) 是:nth-child(|An+B| of S) 的另一种写法。以此类推,还有 nth-last-of-type、first-of-type、last-of-type、only-of-type。
链接伪类选择器
- :any-link 表示任意的链接,包括 a、area 和 link 标签都可能匹配到这个伪类。
- :link 表示未访问过的链接
- :visited 表示已经访问过的链接。
- :target 用于选中浏览器 URL 的 hash 部分所指示的元素。
在 Selector Level 4 草案中,还引入了 target-within、focus-within 等伪类,用于表示 target 或者 focus 的父容器。
行为伪类选择器
- :hover 表示鼠标悬停在上的元素。
- :active 表示用户正在激活这个元素,如用户按下按钮,鼠标还未抬起时,这个按钮就处于激活状态。
- :focus 表示焦点落在这个元素之上。
- :checked 表示一个被点击了的单选框或者复选框
行为伪类选择器是使用频率比较高的一种伪类选择器,我们经常使用它们来实现对单选框和复选框的美化。
逻辑伪类选择器
我们这里介绍一个逻辑伪类 —— :not 伪类,这个我们在上面也已经介绍过了,它代表的是反选,不过我们在实际的使用中使用的并不是特别多。
其实伪类选择器除了上面介绍的还有很多种,不过实际的开发中使用的不是特别多,所以我就不一一罗列了,大家感兴趣的可以自己去了解一下。
通过上面的介绍,我们可以知道,伪类选择器在书写的时候需要使用
:
开头,如下:.checkbox input:checked { attr: value; }
-
-
属性选择器
属性选择器是根据HTML元素的属性来进行元素的选择,因为HTML元素的属性是有值的,所以在属性选择器中是可以书写表达式的,因此,属性选择器在书写的时候需要使用
[]
进行包裹,如下:div[name=divname] { attr: value; }
属性选择器一共有四种书写方式:
-
[attr]
直接在方括号中放入属性名,这种书写方式表示只检查元素是不是具有这个属性,而不关心元素的这个属性的值是什么,这要元素有这个属性,不论这个属性的值是什么,这个元素都可以被选中。
-
[attr=value]
这种书写方式意思是精确匹配,其不仅要求元素要具有名为attr的属性,还要求元素的attr属性的值为value。
-
[attr ~= val1 val2]
多匹配,这种书写方式的意思是要求元素具有attr属性,并且其值是 val1 或 val2…,多个属性值之间使用空格进行分割。
-
[attr |= val]
开头匹配,这种书写方式意思是要求元素具有attr属性,并且属性的值以 val 开头,它跟精确匹配的区别是属性只要以 val 开头即可,后面内容不管。
有些 HTML 属性含有特殊字符,这个时候,可以把 val 用引号括起来,形成一个 CSS 字符串。CSS 字符串允许使用单双引号来规避特殊字符,也可以用反斜杠转义,这样,就可以表示出任意属性值啦。
不过个人建议不要在开发中使用复杂的属性名称和属性值。
-
-
通用(全体)选择器
可以把这个选择器认为是一个通配符,其书写方式如下:
* { attr:value; }
通用选择器其实是一个特殊的元素选择器,它用来选择任意的元素。
在实际的开发中,这个东西使用的是比较少的,只是在css reset 中会使用。css reset是用来去除浏览器自带样式的css代码,写法比较多,现在比较流行的写法如下:
*{ margin:0; padding:0; }
代码是非常简单的,不过争议也很多,有人认为这种写法会影响css的解析性能。
复合选择器
复合选择器是指连续写在一起的简单选择器,**注意,是连续写在一起的,中间不能有任何的分隔符。**复合原则器是针对单个元素自身特征进行选择的。示例代码如下:
div.container[attr=value] {
attr:value;
}
个人认为,css中各种选择器在设计语法的时候是比较巧妙的,我们上面提到元素选择器的写法就是直接书写元素名称就可以了,没有任何特殊的语法,这一点就限制了我们如果要在一个复合选择器中使用元素简单选择器,那么元素选择器只能有一个且必须出现在复合选择器的开头。
这是完全合理的,因为复合选择器针对单一的元素,而一个元素只能是一种类型的元素——要么是div,要么是span或者是别的什么元素,它绝不可能既是div又是span,所以一个复合选择器中只能有一个元素选择器是完全合理的。而且元素选择器的书写方式限制其只能位于复合选择器的开头,这还在无形之中减小了css解析的难度。
复合选择器表示简单选择器中“且”的关系,例如,例如.b.d
,表示选中的元素必须同时具有 b 和 d 两个 class。
复杂选择器
复杂选择器是指有空格
、>
、~
、+
、||
等符号链接的复合选择器。我们前面说过,复合选择器和是针对一个元素自身的特征的,我们可以认为这是一种绝对定位。
但是,HTML文档本身是一个树形结构,这个时候我们定位节点就会有一种非常普遍的相对定位的需求:我不选中这个元素本身,而是要根据一定的位置关系选择满足条件的节点。
复杂选择器就为我们提供了根据父节点
或者前序节点
选择节点的能力。至于为什么只能是根据父节点或者是前序节点呢?我们下文会有介绍。
那么这几种连接符号分别代表了什么呢?
-
空格
后代(也就是所有的下级)其代表的是后代,表示选中所有符合条件的后代节点,例如“ .a .b ”表示选中所有具有 class 为 a 的后代节点中 class 为 b 的节点。
-
>
子代(也就是下面一级)其代表子代,表示选中符合条件的子代节点,例如“ .a>.b ”表示:选中所有“具有 class 为 a 的子节点中,class 为 b 的节点”。
-
~
后继(我们可以称之为弟弟节点)其标识后继,表示选中所有符合条件的后继节点。后继节点即跟当前节点具有同一个父元素,并出现在它之后的节点,例如“ .a~.b ”表示选中所有具有 class 为 a 的后继中,class 为 b 的节点。
-
+
直接后继表示选中符合条件的直接后继节点,直接后继节点即 nextSlibling。例如 “.a+.b ”表示选中所有具有 class 为 a 的下一个 class 为 b 的节点。
-
||
列选择器表示选中对应列中符合条件的单元格,这个连接符比较少用。
我们在实际使用时,比较常用的连接方式是“空格”和“>”。
实践中一般会采用设置合理的 class 的方式,来避免过于复杂的选择器结构,这样更有利于维护和性能。
空格和子代选择器通常用于组件化场景,当组件是独立开发时,很难完全避免 class 重名的情况,如果为组件的最外层容器元素设置一个特别的 class 名,生成 CSS 规则时,则全部使用后代或者子代选择器,这样可以有效避免 CSS 规则的命名污染问题。
选择器列表
选择器列表是指用,
连接的多个复杂选择器,它表示一种或的关系。
其实选择器列表只是一种多个复杂选择器具有相同样式的简写形式,而且我们下面将要介绍的选择器优先级的计算考察粒度为复杂选择器,所以把选择器列表理解为一种简写是最自然的理解方式。
CSS选择器组合的优先级
在 CSS 规则中,选择器部分是一个选择器列表。选择器列表是用逗号分隔的复杂选择器序列;复杂选择器则是用空格、大于号、波浪线等符号连接的复合选择器;复合选择器则是连写的简单选择器组合。
根据选择器列表的语法,选择器的连接方式可以理解为像四则运算一样有优先级。
- 第一优先级
- 无连接符号
- 第二优先级
空格
~
+
>
||
- 第三优先级
- “,”
各级优先级之间的优先级是等同的,结合性是自左向右。
CSS选择器权重
CSS 标准用一个三元组 (a, b, c) 来构成一个复杂选择器的权重。需要注意的是这个计算是计算一个复杂选择器内部的数量
- a 为id选择器的数目
- b 为class选择器和伪类选择器的数目之和
- c 为伪元素和标签选择器的数目之和
*
(通用选择器)不影响优先级
CSS 标准建议用一个足够大的进制,获取“ a-b-c ”来表示选择器优先级,即:
specificity = base * base * a + base * b + c
其中,base 是一个“足够大”的正整数。关于 base,历史中有些趣闻,早年 IE6 采用 256 进制,于是就产生“256 个 class 优先级等于一个 id”这样的奇葩问题,后来扩大到 65536,基本避免了类似的问题。
如果是我们平常写代码的时候,我们只需要根据三元组依次向下比较就行了,不用去计算这个值。
现代浏览器多采用了更大的数量,我们正常编写的 CSS 规则数量不太可能达到数万,因此我们可以认为这样的 base 就足够大了。
行内属性的权重永远高于CSS选择器,浏览器提供了一个“口子”,就是在选择器前加上!import
。
权重相同的选择器遵循“后面的覆盖前面的”原则,如下:
<div id="my" class="x y">text<div>
.x {
background-color:lightblue;
}
.y {
background-color:lightgreen;
}
调换“.x”和“.y”我们可以得到不同的显示效果。
总结
CSS中使用选择器对HTML中的DOM元素进行选择,然后在选择器上施加样式。选择器根据层次的不同可以分为简单选择器、复合选择器、复杂选择器和选择器列表。而一个DOM元素可能会被多个选择器同时命中,这个时候我们就需要计算选择器的优先级,如果在不同的优先级中指定了相同的样式,那么优先级高的选择器中的样式将会生效。
以上就是我对CSS选择器的基本理解,感谢你耐心读完。本人深知技术水平和表达能力有限,如果文中有什么地方不合理或者你有其他不同的思考和看法,欢迎随时和我进行讨论(laomst@163.com)。