在 svg 中需要寫一個 markdown 編輯器,需要用到 <foreignObject> 繪製來html,編輯器選擇了 simplemde。大致html部分結構如下,<markdown-editor> 元件為客製化封裝好的 simplemde 編輯器。
<template> <svg> <g> <foreignObject :width="XXX" :height="XXX"> <div xmlns="http://www.w3.org/1999/xhtml"> <markdown-editor></markdown-editor> </div> </foreignObject> </g> </svg> </template>
在 Chrome 瀏覽器開發完成,測試上線都符合預期,但是最後收到使用者反饋:她用的是 mac 自帶的 Safari 瀏覽器,在 Safari 裡markdown編輯器會出現錯位等各種問題。於是我先開啟我的 Firefox 瀏覽器,自測正常,那估計就是 Safari 瀏覽器的相容問題了。我看了下 Safari 瀏覽器的表現:markdown 編輯器每次一開啟檢查本身的 dom 佔位是正確的,但是可視的編輯器介面卻會被渲染到最頂部 <svg> 標籤的左上角原點(0,0)。最後排查到是因為 safari 對 SVG 中的 <foreignObject> 標籤支援不友好,渲染容易錯位,特別是遇到 position 屬性的時候,而我在引入simplemde 編輯器的同時也引入了 simplemde.min.css,其中大量使用了 position 屬性我也在 StackOverflow 和 Github 找到了幾篇關於這個bug的討論帖作為參考:
StackOverflow:SVG foreignObject not working properly on Safari
Github:Safari + foreignobject render issue
最後Github一位程式設計師ankero一錘定音,原文大意如下:
這不是一個問題,但是可以新增到 README 中。我將在這裡新增它,以便如果有人面臨類似的問題,可以在這個倉庫中找到一個解決方案。在使用這個庫(指的是react-d3-tree庫,但是遇到的問題是一樣的)進行開發時,如果使用 foreignObject 呈現節點,請檢查它在 Safari (Mac + iOS)中的顯示方式。我們遇到了一個問題,節點內容呈現為父 SVG 的座標0,0(左上角)。這是由於 Safari 中的一個 bug,它影響 foreignObject 根據頂部 SVG 而不是 foreignObject 本身計算呈現位置。通過檢查節點並檢視基於瀏覽器的節點是否在應該在的位置,您可以非常清楚地看到這種效果,但是呈現在了錯誤的位置。(這段描述和我當時排查的結果一模一樣)
那麼,如果你看到這個問題,解決方案是什麼?
據我所知,如果您使用以下任何 CSS 選項,dom 元素將呈現在錯誤的位置。所以解決辦法就是不要用這些。對我們來說,我們需要檢查瀏覽器是否是 Safari,然後刪除一些需要一個或多個這樣的樣式的功能。
所以不要在 Safari + foreignObject 中使用以下樣式:
如何檢測 Safari?
我們使用以下片段:
export const IS_SAFARI = /Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor);
這裡提一下 position: fixed 導致的溢位問題,這個在上一個StackOverflow連結中被很多程式設計師提為解決,方案,這個辦法確實能解決一些簡單的需求和頁面,但是需要注意的一點是,使用這種辦法會導致頁面縮放出現問題。具體來說就是svg所繪製元素的縮放比例與<foreignObject>所繪製元素的縮放比例不是一致的,這也會帶來位置錯亂問題。不過可以根據自己的具體情況進行抉擇。
各大瀏覽器之間的相容問題是各位前端er心中永遠的痛,一方面希望谷歌或火狐瀏覽器能一統江湖,但是另一方面又希望百家齊放能促進前端技術的發展。但是話說又說回來,最重要的還是遵守標準,既然標準都設立在那了,為啥各家不跟上標準呢。