hrefにすべきか、xlink:hrefにすべきか、それが問題だ(SVG)

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の廃止に備えて、hrefxlink: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はアニメーションさせることを前提として作られていますので、多くのプロパティ2element.propertyNameで直接アクセスできず、element.propertyName.baseValが指定としての値、element.propertyName.animValがアニメーション中の値(読み取り専用)となっています。

hrefをアニメーションさせる場面も考えづらいのではありますが、やはりbaseValanimValのある構造となっていまして、element.href = 'https://...'ではなくelement.href.baseVal = 'https://...'のように指定する必要があります(なお、この構造はSVG 1.1とSVG 2.0で特に変わっていません)。


外部リンク





  1. 名前空間URIは、(この例では説明の文書が置いてありますが)URIを使った一意な識別子ですので、https://に書き換えてはいけません。 



  2. DOM操作を考える際に、AttributeとPropertyは区分して考える必要がありますので、「属性」とせずに「アトリビュート」「プロパティ」としています。