伪类(Pseudo-classes)和伪元素(Pseudo-elements)的区别是什么?
伪类(Pseudo-classes)和伪元素(Pseudo-elements)是 CSS 中非常重要但容易混淆的概念。
简单的一句话总结:
- 伪类用于选择DOM树中已经存在的元素(基于状态或位置)。
- 伪元素用于创建DOM树中不存在的抽象元素,或者选中元素的特定部分。
以下是详细的对比和解析:
1. 核心概念区别
伪类 (Pseudo-classes)
- 定义:用于定义元素的特殊状态。它用于选择那些不能通过简单选择器(如 ID 或 Class)直接选中的元素。
- 逻辑理解:你可以把它想象成浏览器在特定条件下自动给元素添加了一个类名。
- 例如:
div:hover相当于当鼠标悬停时,浏览器给 div 加了一个class="hover"。
- 例如:
- 常见例子:
:hover,:active,:focus,:first-child,:nth-child,:checked,:not().
伪元素 (Pseudo-elements)
- 定义:用于设置元素特定部分的样式,或者在元素前后插入内容。它创建了一个文档树中不存在的“虚拟”元素。
- 逻辑理解:你可以把它想象成浏览器在元素内部自动添加了一个新的 HTML 标签。
- 例如:
p::first-line相当于浏览器在段落的第一行文字外包了一个<span>标签。 - 例如:
div::before相当于在 div 内部的最前面插入了一个<pseudo>标签。
- 例如:
- 常见例子:
::before,::after,::first-letter,::first-line,::placeholder,::selection.
2. 语法区别 (: vs ::)
这是面试中常考的细节:
- 伪类:始终使用单冒号 (
:)。- 例:
:hover
- 例:
- 伪元素:
- CSS3 标准规定使用双冒号 (
::),以便与伪类区分。 - CSS2 历史遗留:在 CSS3 之前,伪元素也使用单冒号(如
:before)。为了保持向后兼容,现代浏览器仍然支持旧的写法(:before,:after,:first-line,:first-letter)。 - 最佳实践:除了旧的伪元素外,建议始终使用双冒号 (
::) 来表示伪元素。
- CSS3 标准规定使用双冒号 (
3. 对比总结表
| 特性 | 伪类 (Pseudo-classes) | 伪元素 (Pseudo-elements) |
|---|---|---|
| 作用 | 描述元素的状态或结构关系 | 创建虚拟元素或选中特定部分 |
| DOM 影响 | 仅改变样式,不产生新元素 | 视觉上创建了新内容,但不在 HTML 源代码中 |
| 标准符号 | 单冒号 : |
双冒号 :: (旧版本兼容单冒号) |
| 数量限制 | 一个选择器中可以同时使用多个伪类 (例: a:hover:first-child) |
一个选择器中只能出现一个伪元素,且必须在最后 |
| 典型示例 | :hover, :focus, :nth-child |
::before, ::after, ::first-line |
4. 代码示例
伪类示例 (:first-child 和 :hover)
这里我们是在操作已经存在的 <li> 标签。
css
/* 选中列表中的第一个 li 元素 */
li:first-child {
color: red;
}
/* 选中鼠标悬停状态下的 li 元素 */
li:hover {
background-color: #eee;
}
伪元素示例 (::before 和 ::first-letter)
这里我们是在创造不存在的内容或选中一部分文本。
css
/* 在 p 元素的内容之前创建一个虚拟元素 */
p::before {
content: "★ "; /* 必须有 content 属性 */
color: gold;
}
/* 选中 p 元素内容的第一个字母(就像给首字母加了个 span) */
p::first-letter {
font-size: 200%;
font-weight: bold;
}
总结
如果你是在根据用户的交互(如点击、悬停)或者元素在列表中的位置来改变样式,用伪类。
如果你是想在页面上加点装饰性的内容(如图标、清除浮动)或者只修改一段文本的一部分,用伪元素。
右滑查看面试常问