根本原因是浏览器不识别:has()语法,Safari 15.4前、Firefox 120及更早、Electron内核低于Chromium 105时整条规则被静默忽略,且.card:has(img)仅检测<img>标签存在性,无法响应加载失败状态。
.card:has(img) .text { width: 100%; } 有时不生效根本原因不是选择器写错了,而是浏览器根本不识别该规则——Safari 15.4 之前、Firefox 120 及更早、Electron 内核低于 Chromium 105 的环境里,:has() 会被静默忽略,DevTools Styles 面板里都看不到这条规则。更隐蔽的问题是:.card:has(img) 只检测 <img> 标签是否存在于 DOM 中,哪怕 src="" 或 src="404.jpg",它也匹配。如果你实际想响应“图片加载失败”,:has() 本身做不到。
.card:has(img) 和 .card:not(:has(img)) 的真实适用场景这两个组合是目前唯一稳定可用的判断逻辑,适用于纯结构层面的样式切换:
.card:has(img) .text → 有 <img> 标签时,文字容器宽度收窄(比如设为 width: 70%),留出图片空间.card:not(:has(img)) .text → DOM 中完全没写 <img> 时,文字撑满卡片(width: 100%),避免空白:has(img:loaded)——它尚未被任何浏览器实现,写了整条 CSS 规则会失效img.error),再写 .card:has(.error)
常见错误是直接给 <p> 或 <span> 设 width,但行内元素对 width 不响应。正确做法是把文字包在一个块级容器里(如 <div class="text">),再对这个容器设宽:
.card .text { display: block;}.card:has(img) .text { width: 65%;}.card:not(:has(img)) .text { width: 100%;}
另外,max-width 比 width 更安全,尤其在响应式布局中;若卡片本身用 flex 或 grid 布局,优先考虑 flex: 1 或 grid-column 控制占比,而非硬设像素或百分比。
立即学习“前端免费学习笔记(深入)”;
如果你试图用 .card:has(img + .text) 这类带 + 的写法,在 Safari 15.4 到 16.3 之间大概率静默失效——它不报错,但样式就是不应用。稳妥方案是放弃兄弟关系依赖,回归最简结构:
<img> 和文字容器是同级子元素.card:has(img) .text 直接后代选择,兼容性最好:has()(如 :has(:has(img))),所有浏览器都不支持@media 或 @supports 里包裹 :has() 规则,旧版 Safari 会直接跳过真正容易被忽略的是 DOM 节点类型干扰:注释、空格文本节点会让 :nth-child() 类选择器偏移,但 :has(img) 不受此影响——只要 <img> 标签在 HTML 里,它就匹配,这点反而比计数类用法更鲁棒。