获取含SVG的DOM元素边界框的正确方式及Firefox下异常问题
getBoundingClientRect在含嵌套SVG的Firefox环境中返回异常结果的解决方案
我来帮你拆解这个问题:你遇到的getBoundingClientRect偏移异常,主要是嵌套SVG的坐标系未正确声明,再加上Firefox 58.x版本的兼容性bug共同导致的,并非getBoundingClientRectAPI本身的问题。
问题根源分析
- 嵌套SVG的视口缺失:你在
nodeicon类的g元素里嵌套了一个独立的<svg>,但这个内层SVG没有设置viewBox属性。当SVG嵌套在另一个SVG内部时,浏览器需要viewBox来明确它的局部坐标系范围;缺失这个属性时,Firefox 58会错误地将内层SVG的x/y定位叠加两次——既算在父容器的transform里,又当成全局SVG的偏移,导致bounding rect被错误放大偏移。 - 坐标系继承冲突:外层g元素已经有
transform="translate(20,20)",内层SVG的x="80" y="68"本应相对于父容器g.nodebox,但旧版Firefox在计算父元素(g.nodeicon)的bounding rect时,错误地将这个x/y解析为相对于最外层SVG的坐标,导致偏移重复计算。
修复方案(二选一即可)
方案1:给嵌套SVG添加viewBox属性
明确内层SVG的视口范围,让浏览器正确解析它的局部坐标系:
<g class="nodeicon"> <svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" x="80" y="68"> <rect height="14" width="14" y="1" x="1" stroke="#888888" stroke-width="1" fill="#ffffff" fill-opacity="0.5"></rect> <line x1="4" y1="8" x2="12" y2="8" stroke="#888888" stroke-width="2"></line> </svg> </g>
方案2:将嵌套SVG替换为g元素
因为你的内层SVG只是简单的图形组合,不需要独立的SVG视口,换成<g>可以彻底避免坐标系冲突:
<g class="nodeicon" transform="translate(80,68)"> <rect height="14" width="14" y="1" x="1" stroke="#888888" stroke-width="1" fill="#ffffff" fill-opacity="0.5"></rect> <line x1="4" y1="8" x2="12" y2="8" stroke="#888888" stroke-width="2"></line> </g>
验证效果
修改后,再调用document.querySelector('.nodes').getBoundingClientRect(),就能得到符合预期的位置和尺寸了。另外需要说明:Firefox后续版本已经修复了这个嵌套SVG的bounding rect计算bug,但如果需要兼容58.x这类旧版本,上述方案可以完美规避问题。
内容的提问来源于stack exchange,提问作者Andreas Mueller
相关产品推荐
相关产品推荐

