伪元素必须用双冒号::,伪类必须用单冒号:;CSS3以此明确语义边界,::用于生成内容(如::before),:用于筛选状态(如:hover),旧写法:before因兼容性被保留但仅限CSS2.1已有伪元素。

伪类用单冒号、伪元素用双冒号是语义强制区分
这不是浏览器“支持不支持”的问题,而是 CSS3 规范明确划出的语义边界:单冒号 : 专属于伪类(如 :hover、:nth-child()),双冒号 :: 强制用于伪元素(如 ::before、::placeholder)。这个改动不是为了增加复杂度,而是为了解决一个真实混淆——:first-letter 看起来像伪类,实际是伪元素;:not() 看起来像伪元素,实际是伪类。双冒号就是个视觉锚点:“这里在造内容,不是在筛状态”。
旧写法 :before 没被砍掉,是因为兼容性不能断
CSS2.1 把 :before 和 :after 定义为伪类,后来 CSS3 才把它们“升格”为伪元素并引入 ::before。如果直接废除单冒号写法,全网存量 CSS 会大面积失效。所以浏览器选择长期保留 :before 的解析能力,但仅限于那些 CSS2 就存在的伪元素(:before、:after、:first-line、:first-letter)。
这意味着:
-
::backdrop、::file-selector-button这类 CSS4 新增伪元素,只认双冒号,写成:backdrop直接被忽略 - 构建工具(如 stylelint)默认报
:before为警告,不是它错了,是你没跟上规范演进 - IE8 及更早只支持单冒号,但 2026 年还考虑 IE8 兼容,基本等于维护古董系统
混用冒号数量会触发隐性失效场景
表面上看 a:hover:before 和 a:hover::before 都能生效,但顺序和组合稍有偏差就会翻车:
立即学习“前端免费学习笔记(深入)”;
-
div::before:hover语法非法 —— 伪元素不能加伪类条件,浏览器直接跳过整条规则 -
p::before::after不合法 —— 一个元素最多一个::before和一个::after,多写一个冒号不会多生成一个节点 -
:not(:hover)必须用单冒号 —— 伪类嵌套伪类,:not(::hover)是无效语法,部分浏览器静默忽略
真正容易被忽略的是:伪元素插入的内容不在 DOM 树中,document.querySelector('div::before') 永远返回 null,哪怕样式渲染出来了。
现代项目该怎么做才不踩坑
别纠结“能不能用”,直接按当前规范落地:
- 所有新写的伪元素,一律用双冒号:
::before、::placeholder、::marker - 伪类永远用单冒号:
:focus-within、:is()、:where(),包括嵌套在:not()里的也必须是单冒号 - 团队代码检查工具里打开
selector-pseudo-element-colon-notation规则,自动拦截单冒号伪元素 - 遇到
::file-selector-button这类较新伪元素时,别查兼容性表了,直接双冒号起步,它本来就不吃单冒号那一套
冒号数量不是风格偏好,是语义开关。写错一个冒号,有时只是 lint 报错,有时是功能静默消失,而且很难 debug。


















