WebKit策略:<foreignObject>可用于绘制svg中的html标签,但与<use>搭配不生效

在<svg>里面可以利用<foreignObject>绘制html标签,原本是我在iconfont采用Font class方式引入svg的无奈之举 。
起初的设计是所有icon先在<defs>中先渲染,以达到icon复用的效果,icon采用Symbol方式引入svg感觉也是比较合适的,比较规范的 。
<template><defs><g v-for="item in list" :key="item._id" :id="'icon-' + item._id"><svg aria-hidden="true" width="16" height="16" x="0" y="0"><use :xlink:href="'#' + item.icon"></use></svg></g></defs></template><script>export default {data() {return {list: [],};},};</script>然后再需要用到的地方用<use :xlink:href="'#icon-' + id" />克隆下来,感觉很完美 。
但是理想很丰满,现实很骨感 。由于某些功能会被影响到 , 不能使用Symbol方式引入 , 最后只能选择Font class引入svg 。于是代码变为了下列
<template><defs><g v-for="item in list" :key="item._id" :id="'icon-' + item._id"><foreignObject width="16" height="16" x="16" y="16"><div xmlns="http://www.w3.org/1999/xhtml"><span class="iconfont" :class="item.icon"></span></div></foreignObject></g></defs></template><script>export default {data() {return {list: [],};},};</script>但是在需要的地方使用<use :xlink:href="'#icon-' + id" />克隆下来,会发现在谷歌浏览器上却完全显示不出<span>标签的内容,即不显示iconfont图标 。
刚开始,我以为是不能在<defs>标签中使用<foreignObject>标签 , 于是我就去查看了SVG规范 , 传送门:https://www.w3.org/TR/SVG/struct.html#DefsElement,SVG规范是支持这种写法的 。打开F12,查看<defs>标签下的dom结构,也可以看到<foreignObject>标签其实是有生成的,也是佐证了这一点 。

WebKit策略:&lt;foreignObject&gt;可用于绘制svg中的html标签,但与&lt;use&gt;搭配不生效

文章插图
但是查看引用<use>标签的地方 , 就没有生成对应的<foreignObject>标签 , 我查看SVG规范文档并没有提到<use>标签不能与<foreignObject>标签共同使用的限制 。最后我打开了github,在w3c的【SVG工作组规范】项目下寻找答案,传送门:https://github.com/w3c/svgwg,最后找到了一个讨论:https://github.com/w3c/svgwg/issues/511 。这位程序员在讨论中说除了 Gecko 之外的所有浏览器都限制<svg:use>元素中的<foreignObject>,他在思考为什么Gecko之类的浏览器允许这么做 。
WebKit策略:&lt;foreignObject&gt;可用于绘制svg中的html标签,但与&lt;use&gt;搭配不生效

文章插图
这下就有点头绪了,原来是浏览器内核原因 。那简单,我们找个Gecko内核的浏览器验证下就知道了,Gecko内核最出名的就是FireFox浏览器(火狐浏览器)了 。其实我的电脑也装了火狐浏览器,但是由于我开发一直用的是谷歌浏览器 , 确实也是好久好久没打开火狐了,放着吃灰,这次也确实没想到可能是浏览器本身的问题 。打开火狐浏览器,果然能显示<span>标签的内容 , 即显示了iconfont图标 。
WebKit策略:&lt;foreignObject&gt;可用于绘制svg中的html标签,但与&lt;use&gt;搭配不生效

文章插图
不过为什么会出现这样的情况呢,另一个叫Dirk Schulze的程序员表示:出于复杂性的原因,WebKit不允许引用foreignObject 。我们没有时间查看所有影响(包括安全影响),如果内容是基于HTML的,那么对foreignObject的支持永远不会很好 。(Blink修复了后半部分)
也就是说Blink内核修复了后半段 , 使浏览器更好的支持了<foreignObject>标签,但是对于引用<foreignObject>标签的情况,还是没有任何进展 。那也就是说谷歌浏览器现在是支持的<foreignObject>标签的 , 只是不支持被<use>标签引用 。
最后直接弃用<defs>和<use>,在需要的地方直接渲染 。简单粗暴,最有效 。
<foreignObject width="16" height="16" x="16" y="16"><div class="icon-div" xmlns="http://www.w3.org/1999/xhtml"><span class="iconfont" :class="classRef.ModuleClassType.Icon"></span></div></foreignObject>虽然不够优雅,但是真香 。
事情原本到这就应该结束了,但是我还是不死心 , 不知道为什么WebKit要做这样的一个策略 。最后,功夫不负有心人,我在Bugzilla又找到了一个提交给WebKit的bug:https://bugs.webkit.org/show_bug.cgi?id=91515 。底下有一名名为Nikolas Zimmermann的程序员对此进行了回应:
WebKit策略:&lt;foreignObject&gt;可用于绘制svg中的html标签,但与&lt;use&gt;搭配不生效

文章插图
原文大意是:
是的 。由于与foreignObject相关的潜在问题,我们故意禁止它 。它需要经过充分测试 , 仅此而已 。

推荐阅读