TL;DR
事象
svgタグをネストした場合に、ネストしているsvgタグに勝手にxmlns=""
が付加されていた。(ChromeとFirefoxで再現。Safariは再現しない)
何が起こる?
表示して欲しいsvg(ネストしているsvg)が表示されない。
解決策
- ネストするsvgを作るときにちゃんとxmlnsを指定しておく。
- 勝手に付加された
xmlns=""
を削る。 - 事前に
setAttribute
でxmlnsを指定してあげる。
はじめに
そもそも何をしたかったのかと言うと、svgでテンプレートを作っておいて、後から作成したsvgをそのテンプレートに埋め込んでダウンロードさせたかった。
svgはネストできるので、問題なくできるだろうと思っていたら意外とハマった、という話の備忘録。
事象
まず、以下のコードをjsfiddleとかで実行すると再現できると思います。(2017/12/28現在のChromeとFirefoxでは再現確認)
本来のコードではちゃんとwidthとかviewboxとか様々指定していますが、今回は事象再現のためだけに簡略化しています。
const parser = new DOMParser();
const doc = parser.parseFromString( `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg>`, "image/svg+xml" );
const templateSVG = doc.childNodes[ 0 ];
const savingSVG = parser.parseFromString( `<svg></svg>`, "image/svg+xml" ).firstElementChild;
templateSVG.appendChild( savingSVG );
console.log(doc.documentElement.outerHTML);
ChromeかFirefoxで実行した結果、コンソールに出力されるのは以下のような文字列です。
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><svg xmlns=""/></svg>
Safariだと以下になります。
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><svg/></svg>
差としては、ネストされているsvgの属性に、勝手にxmlns=""
が付加されているかどうか。
この状態のsvgをBlobにしてダウンロードして、それを開くとあら不思議。
ネストしたsvgの方だけ表示されない。。。
ちなみに、ネストしている方のsvgを単体で保存した場合にはちゃんと表示されます。
原因と解決策
調べてみると、どうやらタイミング的にはouterHTMLで書き出した時に<svg xmlns=""></svg>
といった具合にxmlns=""
が補完されていました。
xmlns=""
を削れば動きます。
ただ、outerHTMLをすると勝手についてしまうので、ちゃんとsetAttribute
でxmlns
の値を指定してあげました。
これで解決!
const parser = new DOMParser();
const doc = parser.parseFromString( templateString, "image/svg+xml" );
const templateSVG = doc.childNodes[ 0 ];
const partSVG = parser.parseFromString( svgString, "image/svg+xml" ).firstElementChild;
// xmlnsは必須。ない場合はouterHTMLで勝手にxmlns=""が追加され、結果的に表示されない。
partSVG.setAttribute( "xmlns", "http://www.w3.org/2000/svg" );
templateSVG.appendChild( partSVG );
console.log(doc.documentElement.outerHTML);
ただ、そもそも上記のコードでいうところのsvgString
を作る際にxmlnsを指定しておけば良かったという。。。