伪类匹配元素状态,伪元素创建匿名渲染节点;伪类用单冒号、伪元素用双冒号;伪类可叠加,伪元素限::before和::after各一个。

伪类和伪元素不是命名习惯问题,而是 DOM 是否真实存在、能否被 JS 操作的根本差异。 写错冒号(比如 :before 或 ::hover)浏览器大概率不报错,但语义完全错位,后续维护和协作会出问题。
伪类选状态,伪元素造内容
伪类匹配的是已有元素在特定条件下的状态或位置,比如用户悬停、表单验证失败、第 3 个子节点——它不新增任何节点,document.querySelector('a:hover') 能拿到真实 DOM 元素。伪元素则创建一个浏览器渲染时才存在的匿名节点,比如 ::before 插入的图标、::first-letter 包裹的首字符——它不在 HTML 中,document.querySelector('p::before') 返回 null,也无法用 JS 绑定事件。
常见误判:
- 把
li:nth-child(2)当成“第二个li”——其实是“父容器下第二个子元素,且恰好是li” - 对
span::first-letter直接写样式——无效,::first-letter只对块级元素生效,得先加display: block - 试图用
div::before::before叠加装饰——违反规范,一个元素最多只能有::before和::after各一个
:hover 是伪类,::before 是伪元素,冒号不能混用
CSS3 明确规定:伪类必须用单冒号 :,伪元素必须用双冒号 ::。虽然 :before 这种旧写法仍被浏览器兼容,但它只是历史遗留,不代表正确;而 ::hover 或 :first-letter 这类写法,要么无效,要么语义错误。
实际影响:
-
a:hover和a::before可以共存,但a::hover语法错误,不会触发悬停效果 -
::selection是全局伪元素,不绑定具体标签,也不受双伪元素数量限制 - 新特性如
:has()是伪类(注意:不是::has),用于父元素条件判断,但它依然不生成新节点
content 属性只对伪元素强制要求
::before 和 ::after 必须声明 content,否则不渲染;而 ::first-letter、::selection 等可省略 content,因为它们修饰的是已有内容片段。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
容易踩的坑:
-
.btn::before { content: ''; background: url(icon.svg); }—— 空content不代表没内容,它只是不可见字符串,仍会占位 -
p::first-line { font-weight: bold; }有效,但加content: 'x'会报错或被忽略 -
input::placeholder的content由浏览器自动生成,开发者不能重写它的值,只能改样式
一个元素最多两个伪元素,但伪类可以叠加
button:hover:active:focus 合法,三个伪类同时生效,优先级按顺序叠加;但 div::before::after::first-letter 是非法的——规范硬性限制一个元素只能有两个伪元素:::before 和 ::after(::marker 在 li 上属于例外,因作用目标不同)。
替代方案:
- 想实现多层装饰(比如带边框+阴影+图标),用 wrapper 元素套一层,再分别加伪元素
- 需要在已用
::before的按钮上控制文字换行,::first-line可能失效(尤其内容为空或纯图标),应检查是否真有可换行文本 -
:is()和:where()是伪类,用来简化选择器组合,不影响伪元素数量限制
真正难的不是记住语法,而是判断「这个效果该用状态筛选,还是该用虚拟节点」——比如高亮搜索关键词,得用 JS 动态包裹 span;但仅给段落首字加大加色,::first-letter 就够了。混淆这两者,代码会越写越绕,也越难调试。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










