CSS规范禁止在img、input等可替换元素上使用::before/::after,因其无内容流可挂载伪元素;浏览器直接跳过解析,不生成渲染节点;正确做法是将伪元素应用于其容器元素。
浏览器不为 img 生成内容流(content flow),而 ::before 和 ::after 必须依附于一个有内容流的宿主才能插入虚拟节点。这是 CSS 规范明确规定的限制,不是浏览器 bug,也不是兼容性问题。
你写 img::after { content: "★"; },DevTools 的 Elements 面板里完全看不到该伪元素;Styles 面板中这条规则会被标记为“无效”或直接不显示——它压根没进入样式计算流程。
哪怕给 img 加上 display: block、position: relative 或 isolation: isolate,也无法绕过这一层规范拦截。
所有可替换元素(replaced elements)都一样:
input、textarea、select、button(部分浏览器下 button 有例外,但不可依赖)iframe、video、audio、canvas
content 属性生成的伪元素本身,也不能再被套用 ::before/::after
它们的共同点是:渲染行为由外部资源或浏览器原生控件接管,CSS 无法在内部插入内容。
常见误判来源有三个:
::after 当成了 img 自身的(比如写了 .wrap::after 却以为是 img::after)onerror 时加 div),误以为是伪元素渲染img::before 显示内容——这是现代浏览器(Chrome/Firefox)对失败状态的特殊放宽,仅限于 src 为空或 404 场景,且不保证跨浏览器一致这种“例外”不能作为通用方案依赖,尤其在生产环境涉及 Safari 或旧版 Edge 时极易失效。
核心原则只有一条:把伪元素移到容器上。
div 或 figure 包裹 img,设 position: relative
::after,再用 position: absolute + top/right 定位到右下角img[alt] + attr(alt) 配合 text-overflow 截取,而非强求伪元素挂载在 img 上最容易被忽略的是:伪元素的定位基准永远是其宿主元素的 border box,而 img 没有这个“盒子”来承载它——这个底层事实决定了所有绕行方案都必须从容器开始设计。