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相關的潛在問題,我們故意禁止它 。它需要經過充分測試 , 僅此而已 。

推薦閱讀