LoginSignup
28
17

More than 3 years have passed since last update.

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

Posted at

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は区分して考える必要がありますので、「属性」とせずに「アトリビュート」「プロパティ」としています。 

28
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
17