概览
CSS选择器可以分为4类:选择器、选择符、伪类、伪元素。
一、CSS选择器的优先级问题
我们可以分为6个等级:
| 等级 | 包含 | 示例 | 权重(辅助判断) |
|---|---|---|---|
| 0级 | 通配选择器、选择符、逻辑组合伪类 | *、(空格、>、+、~、||)、:not等 | 0 |
| 1级 | 标签选择器 | div | 1 |
| 2级 | 类选择器、属性选择器、伪类 | .xxx、[xxx]、:hover | 10 |
| 3级 | ID选择器 | #xxx | 100 |
| 4级 | style内联属性 | style="color: red;" | 1000 |
| 5级 | !import | .xxx{color: red !important} | 10000 |
1.1 判断CSS选择器优先级
采用数值计算法:将包含的所有CSS选择器类型的权重相加,值越大,优先级越高。
不过,权重仅供参考,一般情况下选择器之间的等级是无法跨越的。就算100个1级选择器(100 * 1),其优先级也不能高于1个2级选择器(1 * 10)。
1.2 当两个CSS选择器的优先级相同怎么办?
后来居上原则:优先级相同,取最后一个CSS选择器样式。
看下面的代码,你觉得文字的颜色应该是哪个呢?
.box {}
.xx {color: red;}
.yy {color: yellow}
<div class="box xx yy">hello css</div>
字体显示yellow。这里可以看作有两种CSS选择器行为:box xx、box yy,两者的权重都是相同的 10 * 2,但是yy在xx后面定义了。根据后来居上原则,我们最终生效的是box yy 样式。
二、选择器
1.元素选择器
这里元素选择器包含了标签选择器和通配符选择器。
需要注意的是,元素选择器不支持级联写法,例如:
// 错误的
divdiv {}
.xxxdiv {}
// 支持的
div.xxx{}
1.1 标签选择器
标签选择器就是 div 、a等html元素标签形式的选择器。不区分大小写。
1.2 通配符选择器
通配符选择器使用方式:*,代表所有类型的标签元素,不包括伪元素。
2.属性选择器
有5种形式:[attr]、[attr='value']、[attr~='value']、[attr|='value']、属性值正则匹配选择器。
2.1 [attr]
属性包含选择器,只要标签上有这个属性就生效样式。例如<button primary></button>,那么button[primary]的样式就会生效。
2.2 [attr='value']
属性值完全匹配选择器,只有标签上完全匹配attr=value才会生效。
例如:预先定义button[type='primary']的样式,则<button primary></button> 不会生效,<button type='primary'></button> 会生效。
注意事项:不区分单引号、双引号,可以删除引号。
2.3 [attr~='value']
属性值单词完全匹配选择器,属性值中单词完全匹配 value 才会生效。
这个怎么理解呢?看如下代码:
[attr~=my] {color: red;}
// 不生效
<div attr='xx ymy world'>hello<div>
// 生效
<div attr='xx my world'>hello<div>
2.4 [attr|='value']
属性值开头片段匹配选择器,属性值以value开头,后面只能接'-'或都不接时才会生效。
参考下列代码:
[attr|=ni] {color: red;}
<div attr="ni">hello</div> // 生效
<div attr="ni-xxx">hello</div> // 生效
<div attr=" ni">hello</div> // 不生效
<div attr="xxx ni">hello</div> // 不生效
<div attr="nixxx">hello</div> // 不生效
<div attr="ni_xxx">hello</div> // 不生效
2.5 属性值正则匹配选择器
- [attr^='xxx']: 开头匹配选择器。(属性值中以xxx开头,xxx前面不能有空格)
- [attr$='xxx']: 尾部匹配选择器。(属性值以xxx结尾,xxx末尾不能有空格)
- [attr*='xxx']: 字符匹配选择器。 (属性值中有xxx)
特别注意:这三者都不能匹配空,例如:[attr^='']。想想也是,如果需要匹配空,可以直接使用属性包含选择器了。匹配空格是可以的,例如:[attr^=' ']。
三、选择符
1.后代选择符(空格)
匹配所有的子元素,使用示例:
div span {color: red;}
<div>
<span>hello</span>
<span>hello</span>
</div>
2.子选择符(>)
匹配第一代的所有子元素,使用示例
xx > yy {color: red;}
<div class="xx">
<div class="yy"></div> // 生效
<div class="yy"></div> // 生效
<div>
<div class="yy"></div> // 不生效
<div class="yy"></div> // 不生效
</div>
</div>
3.相邻兄弟选择符(+)
匹配相邻元素,使用示例:
div + div {color: red;}
<div>hello</div>
<div>hello</div> // 红色
4.随后兄弟选择符(~)
匹配后面的所有兄弟元素,使用示例:
div ~ div {color: red;}
<div>hello</div>
<span>111</span>
<div>hello</div> // 红色
<div>hello</div> // 红色
5.注意事项
选择符有一些相同的注意事项:
(1) 相邻兄弟节点之间会忽略文本节点。
(2) 相邻兄弟节点之间会忽略注释节点。
个人觉得,这是因为文本节点和注释节点并非是一个元素节点所产生的忽略情况(元素是由开、闭标签和包裹内容组成)。例如:
div + div {color: red;}
<div>hello</div>
hello
<!-- 注释 -->
<div>hello</div> // 红色
四、伪类
1.用户行为伪类
有这些伪类::hover、:active、:focus、:focus-within、:focus-visible。
(1) :hover。鼠标移过生效
(2) :active。鼠标按住生效
(3) :focus。鼠标或键盘触发的聚焦。(仅限于:非disabled状态的表单元素 <input> 等、含有href的<a>、<area>、<summary>)
(4) :focus-within。鼠标或键盘触发的聚焦,和:focus区别是其只要包含的子元素聚焦了,当前元素就聚焦。
(5) :focus-visble。键盘触发的聚焦。(适用场景:鼠标点击需要隐藏轮廓,键盘聚焦显示轮廓)
2.URL行为伪类
有这些伪类::link、:visited、:any-link、:target、:target-within。
(1) :link。匹配页面上没有访问过的a标签。
(2) :visited。匹配页面上已访问过的a标签。(注意事项:不支持透明颜色、设置属性必须在a标签样式中事先定义过、getComputedStyle只能获取a标签颜色,而不能获取a:visited颜色)。
(3) :any-link。匹配所有具有href属性的标签,例如:a、link、area标签。(其也匹配所有的:link、:visited元素)。
(4) :target。匹配元素id值等于锚点值的元素(例如:<a id='xxx'> 匹配 #xxx时,匹配a标签样式)
(5) :target-within。只要子元素匹配:target的元素,其就匹配。
3.输入伪类
有这些伪类::enabled、:disabled、:read-only、:read-write、:placeholder-shown、:default、checked、:indeterminate、:valid、:invalid、:in-range、:out-of-range、:required、:optional。
(1)enabled。表单元素包含enabled属性时匹配。
(2)disabled。表单元素包含disabled属性时匹配。(同时包含enabled、disabled,只有disabled生效)
(3)read-only。输入框只读,类似disabled样式。但其可以被表单提交,disabled的元素不能被提交。(只作用于input、textarea元素)
(4):read-write。输入框默认样式(只作用于input、textarea元素)
(5):placeholder-shown。输入框placeholder有值时匹配。
(6):default。只匹配默认状态的表单元素。
(7):checked。只匹配标准表单控件元素。
(8):indetermiate。主要匹配复选框半选样式(还会对radio、progress有影响,不常见故此处不做介绍)
(9):valid。匹配输入值有效的表单元素。
(10):invalid。匹配输入值非有效的表单元素。
(11):in-range。匹配输入框值在min和max之间的元素。(number或range类型的输入框)。
(12):out-of-range。匹配输入框值在min和max之外的元素。(number或range类型的输入框)。
(13):required。匹配了设置requried属性的表单元素。
(14):optional。没有设置required属性的表单元素。(与:required相反)
4.树结构伪类
有这些伪类::root、:empty、:first-child、:last-child、:only-child、:nth-child()、:nth-last-child()、:first-of-type、:last-of-type、:only-of-type、:nth-of-type()、:nth-last-of-type()。
(1):root。表示的就是html元素。
(2):empty。匹配空标签元素(注意:标签中不能有空格、换行)。
(3):first-child。匹配第一个元素。
(4):last-child。匹配最后一个元素。
(5):only-child。匹配没有兄弟元素的元素。
(6):nth-child()。匹配符合括号内规则元素。(参数可选:odd,即1、3、5等奇数行;even,即2、4、6等偶数行;n的运算规则,例如:2n、3n + 1,n为大于等于0的整数)
(7):nth-last-child()。从后往前,匹配符合括号内规则元素。(参数和nth-child()一样,只不过从后往前数)。
(8):first-of-type。匹配当前标签元素类型的第一个。
(9)last-of-type。匹配当前标签元素类型的最后一个
(10):only-of-type。匹配只有一种的标签元素类型(即不能拥有同类型标签兄弟元素)。
(11):nth-of-type()。匹配当前标签元素类型的第几个(参数同nth-child())
(12):nth-last-of-type()。从后往前,匹配当前标签元素类型的第几个(参数同nth-child())。
这里,出一道非常容易出错的题:请问B的颜色是什么?
div { color: black; }
div:first-child { color: red; }
<span>A</span>
<div>B</div>
<span>C</span>
<div>D</div>
答案是:黑色。因为选择器从右往左解析,先判断是第一个元素,再判断是否是div标签。很明显第一个元素是span标签元素,所以div:first-child未生效,B的颜色就是div定义的默认样式黑色。
5.逻辑组合伪类
有这些伪类::not()、:is()、:where()。
(1)not()。当括号中选择器不匹配时,匹配当前元素。
(2)is()。只要括号中任一个参数匹配,匹配当前元素。(例如: :is(.xx, .yy) + div,等价于.xx + div, .yy + div {})
(3)where()。与is()意义相同,任一参数相同则匹配。(区别:where优先级始终为0,is优先级为参数中优先级最高的一个)
6.其他伪类
有这些伪类::scope、:host、:host()、:host-context()、:fullscreen、:lang()
(1):scope。在CSS中效果等级于:root。
(2):host。匹配shadow的根元素。
(3):host()。根据元素id、类名、属性匹配shadow根元素(例如::shadow(.xxx)、:shadow([name='hello']))。
(4):host-context()。根据父元素来匹配shadow根元素(例如: :shadow(.xxx),其中.xxx是父标签的类)。
(5):fullscreen。匹配全屏元素的样式。
(6):lang()。匹配网页的语言,需要在html标签上设置lang。(例如:a:lang(zh)会匹配 <html lang='zh'> 或 <html lang='zh-SG'> 下的 a标签)
五、伪元素
伪元素和伪类不一样的地方,是它的前面是(::)。常见伪元素有: ::before、::after、::first-letter、::first-line等等。
(1)::before伪元素会在元素之前渲染,意味着可能::before伪类内容会被元素遮住。
(2)::after伪元素会在元素之后渲染,所以有时候可以用作"角标",展示在右上角。(感兴趣的同学可以研究下css属性content,有一个角标的实现方案是利用content显示元素属性值,元素属性值绑定角标数字)
(3)::first-letter伪元素会匹配元素的第一个字母。
(4)::first-line伪元素会匹配元素的第一行。
伪元素和伪类的区别:(1)符号不同:伪类(:), 伪元素(::)。(2)意义不同:伪类是让选中元素整体生效,伪元素是让选中元素的某个部分生效。
(tips: 其余的伪元素可以自行查阅相关资料,受限于篇幅此处不做收纳)