:has()无法判断图片是否加载成功,仅匹配DOM中是否存在img标签,不感知网络状态或加载失败;真正识别失败需JS监听error事件并添加类,再用:has(.img-error)响应。

:has() 无法根据图片是否加载成功设占位图——它只认 DOM 结构是否存在 img 标签,不感知网络状态、加载失败或懒加载时机。
为什么 :has(img) 不等于“图片已加载”
:has(img) 在 HTML 解析完成时就匹配了,哪怕 src 是空字符串、404 路径或 loading="lazy" 还没触发请求。浏览器根本不会等图片下载完再计算样式。
-
<img src="">→ 匹配:has(img) -
<img src="broken.jpg">(返回 404)→ 依然匹配 -
<img src="valid.jpg" loading="lazy">(尚未进入视口)→ 仍匹配
真正能区分“加载失败”的只有 JS:监听 error 事件并加 class,比如 .img-error。
用 :has(.img-error) 实现加载失败占位图
先让 JS 捕获失败并打标:
立即学习“前端免费学习笔记(深入)”;
<img src="photo.jpg" onerror="this.classList.add('img-error')">
再用 CSS 响应:
.card:has(img.img-error) .placeholder {
display: flex;
}
.card:has(img.img-error) img {
display: none;
}
- 必须用
onerror或addEventListener('error'),img:load伪类不存在且不被支持 - 不要写
:has(img:error)——:error不是标准伪类,浏览器直接忽略整条规则 - 确保
.placeholder在 DOM 中真实存在(不能靠 JS 动态插入后才指望:has()生效)
Safari 下 :has() 占位图静默失效的常见原因
Safari 15.4+ 支持基础 :has(img),但对复合条件敏感:
- 写了
.card:has(img):has(.img-error)→ Safari 只支持单个:has(),第二个会被丢弃 - 用了
img[src*="cdn"]加属性判断 → Safari 对属性选择器在:has()内解析更保守,建议改用 class 判断 - 卡片容器加了
content-visibility: auto→ 会阻断:has()计算,临时移除可验证
真正在意加载状态的场景,CSS 层面只能靠 class 驱动;:has() 是开关,不是传感器。


















