伪类必须用单冒号,伪元素必须用双冒号是w3c自css3起确立的硬性解析规则;写错冒号数量会导致浏览器直接忽略整条规则,devtools中不显示,且构建工具会报错。

伪类必须用单冒号,伪元素必须用双冒号是硬性语义分界
这不是浏览器“宽容不宽容”的问题,而是 W3C 自 CSS3 起确立的解析规则:单冒号 : 只能用于伪类(如 :hover、:focus、:not()),双冒号 :: 是伪元素(如 ::before、::placeholder)的唯一合法标识。写错冒号数量,浏览器会直接忽略整条规则,且 DevTools 样式面板里根本不会显示它。
常见错误现象:
-
a::hover { color: red; }—— 静默失效,::hover不是合法伪元素,浏览器不识别 -
input::placeholder { color: #999; }写成input:placeholder—— Chrome 57+、Firefox 51+、Safari 10.1+ 全部丢弃,无警告 - 构建工具如
cssnano或stylelint会报selector-no-vendor-prefix类错误,本质是解析器判定选择器非法
::before 和 ::after 为什么还能用单冒号?但混用很危险
::before 和 ::after 属于 CSS2 就存在的“过渡期伪元素”,所以浏览器至今仍兼容 :before 和 :after。但这不等于推荐混用,更不等于可以随意切换。
实际影响包括:
- 同一项目中同时存在
div:before和div::before,PostCSS 插件可能去重或报冲突 - 某些 CI 构建流程启用严格压缩时,
:before规则可能被cssnano误判为过时语法而丢弃 - 团队协作中看到
p:first-letter,无法立刻判断是伪类还是伪元素——:first-letter是伪元素,但单冒号掩盖了语义
:not() 里只能放单冒号伪类,且不能嵌套伪元素
:not() 是伪类,括号内只接受能匹配真实 DOM 元素的条件。它不认伪元素,也不接受双冒号。
正确写法与典型错误:
- ✅
a:not(:hover):not(:focus)—— 多个单冒号伪类叠加,合法 - ❌
a:not(::hover)—— 语法非法,整个:not()失效 - ❌
input:not(:placeholder)——:placeholder是伪元素,不能进:not(),应改用input:not([placeholder])(属性选择器) - ⚠️
button::before:not(:hover)—— 伪元素不能带状态,顺序颠倒即无效;正确只能是button:hover::before
真正容易被忽略的是渲染层隐性约束
即使语法全对,::before 的样式也可能不按预期显示——比如宿主元素加了 position: relative 和 z-index,它的 ::before 就自动成为子 stacking context,此时需要额外设 z-index 控制层级,否则可能被遮住。
还有几个常被跳过的点:
-
<img>、<input>、<iframe></iframe>等非容器元素不支持::before/::after,因为它们无法插入内容节点 -
::selection在 Safari 16.4+ 开始强制要求双冒号,:selection可能只作用于部分文本范围 -
::backdrop(用于<dialog></dialog>)所有现代浏览器均不响应单冒号写法
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











