重新认识伪类与伪元素
伪类、伪元素都属于 CSS 选择器体系。
伪类用于匹配真实 DOM 中满足特定状态、位置条件的已有元素;伪元素可以选中渲染层面的虚拟盒子,或是对已有 DOM 的文本片段做样式切割,这部分虚拟对象并不出现在 DOM 文档树中。
简单来说:伪类是给现有 DOM 元素增加筛选条件;伪元素可以作用于 DOM 树中没有对应节点的虚拟渲染对象,例如 ::before、::after 生成的装饰盒子,或是段落的首字母、首行文本片段。
伪类是什么?
伪类是用来匹配处于特定状态的元素的选择器,例如 :first-child、:hover。
伪类的效果,就如同给满足条件的 DOM 元素动态附加了一个 class 类名,不需要修改 HTML 源码即可完成样式控制。
伪类语法:以单冒号 :开头。
结构伪类
常用结构伪类列表
也常称为 CSS3 结构类伪类,依靠元素在文档中的位置、层级关系进行匹配。
E:first-child:匹配父元素下第一个子元素,且该子元素必须是 E 标签。若父元素第一个子节点不是 E,则匹配失效。E:last-child:匹配父元素的最后一个子元素,且该子元素类型为 E。E:nth-child(an+b):匹配父元素下,位置序号满足表达式的子元素,同时该元素必须是 E。E:nth-last-child(an+b):从兄弟元素末尾向前计数,匹配序号符合表达式且类型为 E 的子元素。E:nth-of-type(an+b):在父元素中,按同标签类型排序,匹配第 n 个 E 类型元素,会跳过其他类型标签。E:nth-last-of-type(an+b):从末尾向前,匹配父元素内第 n 个 E 类型元素。E:first-of-type:匹配父元素下第一个 E 类型元素。E:last-of-type:匹配父元素下最后一个 E 类型元素。E:only-child:父节点仅有唯一子元素,并且这个子元素是 E。E:only-of-type:父节点子元素中,仅有一个 E 类型标签,其他标签可以存在。E:empty:匹配完全不包含子节点、也没有文本内容的 E 元素(空白文本节点也会让它匹配失败)。:blank:实验性伪类,用于匹配尚未填写内容的表单控件(如空的input、textarea);现行浏览器均未实现。:playing:匹配正在播放的音视频等媒体元素。:paused:匹配处于暂停状态的音视频等媒体元素。:root:文档根元素,等同于<html>,选择器优先级高于普通html。:scope:在全局样式表中使用,等价于:root;在@scope规则内匹配该作用域的根元素;在 DOM API(querySelector、querySelectorAll、matches)调用时,代表调用该方法的元素,作为选择器的查找上下文。:target:匹配 URL hash(锚点片段)所指向 id 的元素。:is(A,B,C):接收选择器列表,匹配列表中任意一条选择器命中的元素,用于精简冗长的选择器。权重取括号内最具体那一条。:where(A,B,C):匹配规则与:is()相同,但权重始终为 0。:not():否定伪类,匹配不满足括号内选择器条件的元素,也叫反选伪类。
:nth-child(an+b) 表达式规则
对全部兄弟子元素从 1 开始编号,筛选序号满足表达式 an+b 的元素(n 取值:0、1、2、3……)。
注意:子元素下标从 1 开始,不存在第 0 位;书写顺序必须 an 在前、b 在后,不能写为 b+an,否则整个选择器会被浏览器忽略,不会匹配任何元素。
/* 第 3 行 */
tr:nth-child(3) {}
tr:nth-child(0n+3) {}
/* 第 4、7、10、13 行 */
tr:nth-child(3n+4) {}
/* 表格奇数行 */
tr:nth-child(2n+1) {}
tr:nth-child(odd) {}
/* 表格偶数行 */
tr:nth-child(2n) {}
tr:nth-child(even) {}
/* 匹配父容器下前 3 个 span */
span:nth-child(-n+3) {}
:not() 否定伪类
权重规则::not() 本身不增加选择器权重,整体权重由括号内部的选择器决定。
旧版浏览器不支持括号内传入多选择器、复杂选择器:
/* 旧版不支持,不能逗号传多条件 */
.element_box :not(.green, .red) {}
/* 拆成两个选择器后语义变成「或」,不是等价写法 */
.element_box :not(.green),
.element_box :not(.red) {}
/* 旧版不支持复杂选择器 */
:not(.box .item) {}
/* 这不是上一行的拆分等价写法:表示既不是 .box,也不是 .item */
:not(.box):not(.item) {}
逗号是「或」,连续连写才是「与」:
/* 逗号代表「或」,满足其中一个条件就命中,两类元素依旧会被匹配 */
.element_box :not(.green),
.element_box :not(.red) {}
/* 连续拼接代表「与」,同时满足两个否定条件 */
.element_box :not(.green):not(.red) {}
祖先匹配:
:not(article) p 无法实现仅排除 article 内部的 p。该选择器含义为:只要 p 的任意祖先不是 article 就会被选中。
<article>
<section>
<p></p>
</section>
</article>
结果: <section> 会满足 :not(article),导致 p 意外命中。
动态伪类(用户交互伪类)
这类伪类会跟随用户操作,状态动态发生改变,分为锚点伪类、用户行为伪类。
- 锚点伪类
:link:未被访问过的链接;:visited:已经访问过的链接;
- 用户行为伪类
:hover:鼠标悬浮在元素上;:active:鼠标按下瞬间的激活状态;:focus:元素获得焦点(键盘、鼠标点击均可);
:any-link:匹配任意链接,相当于同时匹配:link、:visited。
LVHA(爱恨原则):设置链接样式时,伪类书写顺序必须为:Link → Visited → Hover → Active,顺序错乱会导致后写的状态盖不住先写的状态。
UI 元素状态伪类
专门用于表单控件,匹配控件不同状态。
:enabled:控件处于可用可编辑状态;:disabled:控件被禁用;:checked:单选框、复选框处于勾选;:optional:非必填表单控件;:placeholder-shown:正在展示占位提示文字;:read-only:元素内容只读,不可修改;:read-write:元素内容允许编辑;:required:必填表单控件。
CSS2、CSS3 的伪类
- CSS2 伪类:
:first-child、:link、:visited、:hover、:active、:focus、:lang(); - CSS3 新增大量结构伪类、逻辑伪类(
:nth-child、:not()、:target等);Selectors Level 4 再引入:is()、:where()等。
伪元素是什么?
伪元素用来生成文档树中不存在的虚拟元素节点,像凭空新增 DOM 节点一样去设置样式,而不是给已有元素附加类。
例如:使用 ::before 在元素内容之前插入装饰内容,这些虚拟节点不会出现在 HTML DOM 树,无法通过 querySelector 获取。
伪元素语法标准:双冒号 ::;为兼容旧 CSS2,浏览器兼容部分老伪元素的单冒号写法。
常用伪元素列表
::before:元素原有内容之前生成虚拟盒子;::after:元素原有内容之后生成虚拟盒子;::first-letter:匹配块级内容的第一个字符;::first-line:匹配块级容器的第一行文本;::selection:匹配鼠标选中高亮的文本区域;::placeholder:表单输入框占位提示文字;::marker:列表项目符号(ul、ol的圆点、序号);::backdrop:全屏模式下底层遮罩盒子;::slotted():匹配 Shadow DOM 中<slot>分发出去的元素;::cue:WebVTT 字幕样式;::grammar-error、::spelling-error:浏览器标记的语法、拼写错误文本。
::before、::after 与 content 属性
::before、::after 必须配合 content 属性使用,才会生成虚拟盒子。
content 支持多种类型取值:
.target::after {
content: "附加文本"; /* 字符串 */
content: url("./icon.png"); /* 图片资源 */
content: attr(data-tip); /* 读取元素自定义属性 */
content: counter(myIndex); /* CSS 计数器 */
content: normal; /* 等同于 none,不生成伪元素 */
}
CSS2、CSS3 的伪元素
- CSS2 伪元素:
::before、::after、::first-letter、::first-line; - CSS3 及之后新增:
::selection、::placeholder、::marker、::slotted()、::backdrop等。
伪类与伪元素的区别
语法区别:
- CSS2:伪类、伪元素统一单冒号
:。 - CSS3 规范:伪类:单冒号
:;伪元素:双冒号::。
备注:浏览器向后兼容,老伪元素 :before、:after、:first-letter、:first-line 单双冒号均可识别;新增伪元素强制使用双冒号。
本质区别:
- 伪类:给已存在的真实 DOM 元素附加虚拟类名,改变已有元素匹配条件。等效于手动增加 class。
- 伪元素:创建不在 DOM 树中的虚拟盒子,相当于新增一个看不见的元素。等效于手动新增 HTML 标签。