SVGをHTMLに埋め込んで、動的な画像操作を行おうとしていたのですが、その過程で引っかかる場所が出てきました。
<image>
要素
SVGの中に他の画像を埋め込むための要素として、<image>
という要素があります。もちろんHTML内ならHTML側の<img>
を使っても処理ができるのですが、SVGの枠内に他の画像も取り込める、ということで、場面によっては便利です。
画像URIの指定は…どうする?
で、当然ながら画像を埋め込む以上は、画像URIを指定する仕組みがあります。そして、これはバージョンの変遷により2つの流儀があります。
-
xlink:href
…SVG 1.1時代の表記。XLinkという、別な名前空間(名前空間URIはhttp://www.w3.org/1999/xlink
1)を使う必要があります。 -
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