伪类用单冒号表示状态,伪元素用双冒号生成虚拟内容;:hover等伪类必须单冒号,::placeholder等新伪元素只认双冒号,混用或错序会导致规则被浏览器静默忽略。

伪类和伪元素语义不同,单双冒号是强制区分手段
单冒号 : 只能用于伪类(如 :hover、:focus、:nth-child()),因为它描述的是 DOM 元素的「状态」或「位置」;双冒号 :: 专用于伪元素(如 ::before、::placeholder),因为它代表浏览器在渲染层插入的「虚拟内容节点」。这不是风格偏好,而是 W3C 自 CSS3 起确立的语义契约——混用会破坏解析逻辑。
::placeholder 这类新伪元素根本不用单冒号
从 CSS3 开始新增的所有伪元素,都只定义了双冒号形式:::placeholder、::selection、::backdrop、::file-selector-button。它们在 Chrome 57+、Firefox 51+、Safari 10.1+ 中完全不认 :placeholder 这种写法,规则会被静默丢弃,DevTools 样式面板里都看不到它。
常见错误现象:
-
:placeholder在现代项目中看似生效,实则靠旧版兼容机制苟延残喘,一旦升级构建工具(如 cssnano)或启用严格 lint 规则,就直接失效 -
::file-selector-button写成:file-selector-button—— 所有浏览器都不识别,且无任何提示
:not() 里写错冒号数量会导致整条规则被跳过
:not() 是伪类,括号内只接受合法伪类,且必须是单冒号。哪怕只多打一个冒号,整个选择器就废了:
立即学习“前端免费学习笔记(深入)”;
-
a:not(::hover)→ 语法非法,浏览器忽略整条规则 -
input:not(::placeholder)→::placeholder是伪元素,不能进:not(),同样失效 -
button:not(:hover)::before→ 正确:伪类在前,伪元素在后;反过来button::before:not(:hover)就无效
真正容易被忽略的是层叠上下文和构建工具行为
即使语法全对,::before 的样式也可能不按预期显示——比如宿主元素加了 position: relative 和 z-index,它的 ::before 就自动成为子 stacking context,此时需要额外设 z-index 控制层级,否则可能被遮住。
构建时更隐蔽的问题:
- PostCSS 插件可能把同选择器下的
:before和::before当作重复规则去重 - cssnano 默认压缩阶段会删掉未识别的选择器,而某些旧版插件对
::backdrop解析失败,导致整条规则消失


















