一、核心定义与本质区别
1. 伪类(Pseudo-classes)
- 定义:用于选中已有元素处于某种状态时的样式,状态由用户行为或元素状态决定(非物理存在的类)。
- 本质:修饰已有元素的某个状态,类似为元素添加临时“类名”。
- 示例:
:hover
(鼠标悬停)、:active
(点击激活)、:checked
(表单选中)。
2. 伪元素(Pseudo-elements)
- 定义:用于在已有元素的内容前后插入虚拟元素,这些元素并非真实DOM节点,而是CSS渲染的产物。
- 本质:创建新的虚拟元素并附加到选中元素,类似
appendChild()
或prependChild()
的效果。 - 示例:
::before
(内容前插入)、::after
(内容后插入)、::first-line
(首行样式)。
二、语法与规范差异
1. 符号区分(关键考点)
- 伪类:使用单冒号(
:
)+ 状态关键词,如:hover
、:nth-child(2)
。 - 伪元素:CSS3规范要求使用双冒号(
::
)+ 元素关键词,如::before
、::selection
。- 例外:
::first-letter
、::first-line
等旧版伪元素仍可兼容单冒号,但建议统一用双冒号。
- 例外:
2. W3C规范演进
- CSS2.1:未严格区分伪类与伪元素,均使用单冒号(如
:before
)。 - CSS3:明确用双冒号标识伪元素(
::before
),单冒号保留给伪类,避免语法歧义。
三、功能场景与实例对比
1. 伪类:状态化样式控制
-
典型场景:
- 交互反馈:按钮悬停
:hover
、链接访问状态:visited
; - 表单状态:
:focus
(获取焦点)、:disabled
(禁用); - 结构筛选:
:nth-child(odd)
(奇数行)、:first-child
(首个子元素)。
- 交互反馈:按钮悬停
-
代码示例:
/* 按钮悬停变红色 */ button:hover { color: red; } /* 选中的复选框样式 */ input:checked { border-color: green; }
2. 伪元素:虚拟内容插入
-
典型场景:
- 装饰性元素:用
::before
和::after
绘制箭头、边框; - 文本样式:
::first-letter
首字母大写、::selection
选中文本高亮; - 清除浮动:
::after
配合content: ''; clear: both;
。
- 装饰性元素:用
-
代码示例:
/* 元素前添加图标 */ .icon::before { content: '📌'; /* 必须指定content属性 */ margin-right: 5px; } /* 段落首行变色 */ p::first-line { color: blue; }
四、性能与渲染差异
1. 对DOM的影响
- 伪类:不修改DOM结构,仅添加样式,性能消耗低;
- 伪元素:虚拟元素需浏览器渲染,相当于增加“隐式DOM节点”,但无需操作真实DOM。
2. 使用限制
- 伪类:可链式叠加(如
a:hover:active
); - 伪元素:每个选择器中最多出现一次,且需放在伪类之后(如
div::before:hover
)。
五、问题
1. 为什么伪元素要用双冒号?单冒号不行吗?
- 答:
CSS3为区分伪类与伪元素,强制伪元素使用双冒号(::
),避免语法歧义。例如:div:first-child
(伪类:选中首个子元素);div::first-child
(语法错误,因first-child
是伪类,应使用单冒号)。
旧版浏览器兼容单冒号(如div:before
),但新标准建议统一用双冒号以符合规范。
2. 伪元素的content属性必须存在吗?
- 答:
除::first-line
、::first-letter
等少数情况外,必须存在。例如:
若省略.box::before { content: ''; /* 空字符串是合法值,否则伪元素不显示 */ display: block; width: 10px; height: 10px; }
content
,多数浏览器会忽略该伪元素(Firefox除外,但仍建议显式声明)。
3. 伪类和伪元素可以同时使用吗?
- 答:
可以,且需遵循“伪元素在伪类之后”的顺序。例如:/* 悬停时元素后的伪元素变色 */ .btn:hover::after { color: red; }
六、总结
- 伪类:单冒号,表状态,选已有元素的某个状态;
- 伪元素:双冒号,创内容,在元素前后插虚拟节点;
- 核心差异:伪类改状态,伪元素增内容,语法符号是关键。