<use>元素CSS选择器表现的浏览器兼容性问题及规范合规性咨询
这确实是一个涉及SVG <use>元素和CSS伪类选择器的典型浏览器兼容性问题,咱们一步步来拆解你的疑问:
第一个场景:不同浏览器的表现差异
先看你给出的第一段代码:
CSS部分:
.foo { visibility: hidden; } .foo:nth-child(2) { visibility: visible !important; }
HTML部分:
<svg> <circle class="foo" id="a" cx="20" cy="20" r="15"/> <circle class="foo" id="b" cx="20" cy="50" r="15" fill="blue"/> <use class="foo" href="#a" x="70" y="0"/> <use class="foo" href="#b" x="70" y="0"/> </svg>
现象是:Firefox只显示1个圆,Chrome却显示2个圆——看起来像是Chrome的bug?
第二个场景:Firefox的反向表现
再看第二段代码:
CSS部分:
.foo { visibility: hidden; } .foo:nth-child(1) { visibility: visible !important; }
HTML部分:
<svg> <circle class="foo" id="a" cx="20" cy="20" r="15"/> <use class="foo" href="#a" x="70" y="0"/> </svg>
这次Firefox反而显示2个圆,这就引出了你的核心疑问:是不是Firefox把<use>引用的元素复制到Shadow DOM里,而:nth-child会在Shadow DOM的上下文里从1开始计数?
问题根源与规范解释
你的猜测完全正确!这里的核心差异源于浏览器对<use>元素Shadow DOM的处理方式:
- Firefox的处理逻辑:SVG规范(尤其是SVG 2)明确规定,
<use>元素会创建一个开放的Shadow DOM,将引用的元素克隆到这个Shadow DOM中进行渲染。并且外部CSS可以穿透到这个Shadow DOM里,作用于克隆的元素。当你给<use>元素添加.foo类时,这个类会被继承到Shadow DOM内的克隆元素上,此时:nth-child是针对每个Shadow DOM的上下文计数——克隆元素在Shadow DOM里是唯一的子元素,也就是:nth-child(1)。
所以在第二个场景中,.foo:nth-child(1)不仅匹配主DOM里的第一个<circle>,还匹配每个<use>Shadow DOM里的克隆<circle>,因此这两个元素都会被设置为visibility: visible,最终显示2个圆。 - Chrome的旧处理逻辑:早期Chrome并没有遵循SVG 2的规范,它不会让CSS选择器穿透到
<use>的Shadow DOM中,:nth-child只作用于主DOM树里的直接子元素。同时,Chrome里<use>元素的样式不会传递给Shadow DOM内的克隆元素,导致克隆元素不受.foo { visibility: hidden; }的影响,所以第一个场景里两个<use>的克隆元素都会显示,加上主DOM里的第二个<circle>,最终显示2个圆。
规范合规性判断
从SVG 2规范的角度来看,Chrome的旧实现确实违反了规范要求——规范明确要求<use>的Shadow DOM是可穿透的,外部CSS应该能够作用于其中的克隆元素。而Firefox的处理是符合SVG 2规范的。不过随着浏览器的迭代更新,现代Chrome已经调整了这部分行为,现在的表现应该和Firefox趋于一致了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

