前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库CSS pseudo-class vs pseudo-element selectors
CSS层叠与选择器

伪类和伪元素有什么区别?冒号怎么写?

伪类(如 :hover)选的是已有元素在特定状态下的样子。伪元素(如 ::before)创建一个不存在于 DOM 中的虚拟部分。伪类用单冒号,伪元素用双冒号。

前端进阶之旅 · 一题精讲更新于 2026.09.29
CSS#层叠与选择器
先看核心答案读代码示例
理解线索

两者的根本区别

  1. 伪类选已有元素的某种状态,如悬停、聚焦、第几个子元素
  2. 伪元素创建一个 DOM 中不存在的虚拟子元素或选中元素的一部分
  3. 冒号规则伪类一个冒号 :,伪元素两个冒号 ::

CSS2 时代伪元素也用单冒号 :before,CSS3 改成了双冒号 ::before。浏览器为了兼容两种都认,但新代码应该统一用双冒号。

核心回答

先记住这个答案

伪类选的是已经存在的元素在某种状态下的样子,比如 :hover 是鼠标悬停时,:first-child 是身为第一个子元素时。伪元素创建的是 DOM 里不存在的虚拟内容,比如 ::before 插入生成内容,::first-line 选中渲染后的第一行文字。简单说,伪类像是给元素贴了一个「当前状态」的标签,伪元素像是凭空造了一个子节点。

  • 伪类选状态,伪元素选虚拟部分
  • 伪类用 :,伪元素用 ::
  • 伪类可连写,部分伪元素允许嵌套
  • 旧浏览器的 :before 也能用但不推荐

冒号的写法规则

CSS2 时代不区分伪类和伪元素,全用单冒号。CSS3 为了明确区分,把伪元素改成了双冒号。

新旧写法对照CSS
/* 伪类:始终用单冒号 */
a:hover { color: red; }
li:first-child { font-weight: bold; }
input:focus { outline: 2px solid blue; }

/* 伪元素:推荐用双冒号 */
p::before { content: "▸ "; }
p::first-line { font-weight: bold; }
p::selection { background: yellow; }

/* 旧写法也能用,浏览器兼容 */
p:before { content: "▸ "; }

新代码一律用双冒号写伪元素。唯一的例外是如果要兼容 IE8——IE8 不认 ::before 但认 :before。不过现在已经不太需要考虑 IE8 了。

伪类可以连写,伪元素不能

伪类可以叠加,比如 a:hover:focus 同时要求鼠标悬停和键盘聚焦。伪元素不能任意连写,p::before::after 是无效的;但有明确的嵌套例外:若 ::before 设为 display: list-item,可用 ::before::marker 选中它生成的列表标记。

伪类和伪元素可以一起用,但伪元素必须写在最后。p:first-child::first-line 合法,p::first-line:first-child 不合法。

伪类和伪元素的组合CSS
/* 第一个段落的第一行加粗(合法) */
p:first-child::first-line {
  font-weight: bold;
}

/* 鼠标悬停时改变 before 的内容(合法) */
.icon:hover::before {
  color: blue;
}

这种组合在实际项目里很常见。比如鼠标悬停在菜单项上时,让 ::before 里的图标变色。

常见的伪类和伪元素分类

伪类可以分成几大类。动态伪类有 :hover 和 :focus 等。结构伪类有 :first-child 和 :nth-child 等。表单伪类有 :required 和 :valid 等。还有否定和关系伪类如 :not() 和 :has()。

伪元素数量少得多,常用的有 ::before 和 ::after(生成内容)、::first-line 和 ::first-letter(选中文本的一部分)、::selection(选中高亮)、::placeholder(占位文字)、::marker(列表符号)。

回答前,多想一步

容易答错的地方

说不清两者的本质区别
「单冒号是伪类,双冒号是伪元素」只描述了写法,没说清本质。关键区别在于:伪类不创建新东西,只是选中已有元素的某种状态。伪元素会创建一个 DOM 中不存在的虚拟节点或选中元素的一部分文本。
以为伪元素能任意连写
p::before::first-line 无效,不能把任何伪元素都接在另一个后面。::before::marker 是有条件的例外,前提是 ::before 生成列表项。写组合选择器时要查具体伪元素支持的嵌套关系。
试着用自己的话回答

面试官还会怎么问?

before 和 after 创建的内容能用 JavaScript 访问吗?

不能直接访问。document.querySelector('::before') 返回 null,不能给伪元素加事件监听。但可以用 getComputedStyle(element, '::before').content 读取它的样式值。

placeholder 是伪类还是伪元素?

::placeholder 是伪元素,用双冒号,它选中的是输入框里占位文字的虚拟部分。:placeholder-shown 是伪类,用单冒号,它选中的是「正在显示占位文字」这个状态下的输入框元素本身。两者一个改占位文字的样式,一个根据有没有占位文字来选中整个输入框。

marker 伪元素是干什么的?

::marker 选中列表项前面的符号(圆点、数字等)。比如 li::marker { color: red; } 可以只让列表前面的圆点变红,不影响列表内容的颜色。以前要改列表符号的颜色只能用 ::before 模拟,现在用 ::marker 更直接。

从一道题,走向一组知识

把知识连起来

层叠与选择器

revert 用在可继承属性上,值会回到父元素的继承值还是浏览器默认值?

revert 是属性值回退机制,与伪类如何选中元素是两个独立层面。

层叠与选择器

revert 和 revert-layer 有什么区别?分别在什么场景用?

revert-layer 回退当前层声明;伪元素规则同样受层叠层顺序影响。

参考资料

  • CSS:层叠与选择器参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 冒号的写法规则
  3. 伪类可以连写,伪元素不能
  4. 常见的伪类和伪元素分类
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑