SVGをHTMLに埋め込んで、動的な画像操作を行おうとしていたのですが、その過程で引っかかる場所が出てきました。
<image>要素
SVGの中に他の画像を埋め込むための要素として、<image>という要素があります。もちろんHTML内ならHTML側の<img>を使っても処理ができるのですが、SVGの枠内に他の画像も取り込める、ということで、場面によっては便利です。
画像URIの指定は…どうする?
で、当然ながら画像を埋め込む以上は、画像URIを指定する仕組みがあります。そして、これはバージョンの変遷により2つの流儀があります。
-
xlink:href…SVG 1.1時代の表記。XLinkという、別な名前空間(名前空間URIはhttp://www.w3.org/1999/xlink1)を使う必要があります。 -
href…SVG 2からの記法。SVGの名前空間の一部となっています。
別な名前空間の属性を使うのは(後述しますが)煩雑になりますし、SVG 2ではxlink:hrefが非推奨となりますので、hrefで書きたくなるかと思います。
待ったをかけるiOS
ところが、ここで問題になるのがiOS Safariで、iOSでSVGのhref属性に対応したのがiOS 12からと、(2019年7月時点から見て)かなり最近のことなのです。iOS 11以前では、xlink:hrefを使うしかありません(なお、よく互換性が問題となるIE 11でも、hrefには対応しています)。
もちろん、xlink:hrefの廃止に備えて、hrefとxlink:hrefに同じ値を指定しておくという方法もあります。この場合、hrefを認識できる環境ではhrefの値が優先される、とのことです。
JavaScriptとSVG
ちょっと本題から外れる部分もありますが、SVGをJavaScriptで操作したい場合、注意点がいろいろとあります。
ノードやアトリビュートと名前空間
SVGのエレメントはHTMLとは別の名前空間にあるので、document.createElementで生成するとSVGのエレメントだと正しく認識されません。document.createElementNS('http://www.w3.org/2000/svg', 'image')のようにdocument.createElementNSへ名前空間も指定して生成する必要があります。
また、SVG要素に付ける通常のアトリビュート2はSVG名前空間で処理されるので単なるsetAttributeで処理して問題ないのですが、xlink:hrefは別な名前空間になるので、.setAttribureNS('http://www.w3.org/1999/xlink', 'xlink:href', 値)とsetAttributeNSが必要になります。
SVGプロパティの処理
SVGはアニメーションさせることを前提として作られていますので、多くのプロパティ2がelement.propertyNameで直接アクセスできず、element.propertyName.baseValが指定としての値、element.propertyName.animValがアニメーション中の値(読み取り専用)となっています。
hrefをアニメーションさせる場面も考えづらいのではありますが、やはりbaseValとanimValのある構造となっていまして、element.href = 'https://...'ではなくelement.href.baseVal = 'https://...'のように指定する必要があります(なお、この構造はSVG 1.1とSVG 2.0で特に変わっていません)。
外部リンク
-
名前空間URIは、(この例では説明の文書が置いてありますが)URIを使った一意な識別子ですので、
https://に書き換えてはいけません。 ↩ -
DOM操作を考える際に、AttributeとPropertyは区分して考える必要がありますので、「属性」とせずに「アトリビュート」「プロパティ」としています。 ↩ ↩2