2012年12月18日火曜日

svgのpreserveAspectRatio属性の動作検証

svgで画像を読み込む際,画像のリサイズ方法を指定するためにpreserveAspectRatio属性が定められています.

これはラスタ画像を読み込む分には単純なのですが,いざ外部のsvg画像を読み込むとなると非常にややこしいことになります.ですので,それらを整理するための検証コードを記述して見ました.

preserveAspectRatio属性とは


svgから外部の画像を読み込む場合,image要素を用います.この時image要素が定める描画領域のサイズと読み込む画像のサイズとの間に差があった場合,何らかの方法で画像の引き伸ばし処理が必要となります.この引き伸ばし方法を指定するものがpreserveAspectRatio属性です.

引き伸ばし方には概ね3つの方法があり,これらと画像を拡大するための基準を表す値「xMinYMin〜xMaxYMax」とを組み合わせることで引き伸ばし処理を定義します.
  • 描画領域いっぱいに引き伸ばす「none」
  • 縦横比を維持しつつ画像が描画領域にすっぽりとおさまる「meet」
  • 縦横比を維持しつつ縦か横を最大限広げる「slice」

svg画像を読み込む場合の問題点


ラスタ画像を読み込む分にはこれだけで良いのですが,svg画像を読み込む場合,話がややこしくなります.というのも,このpreserveAspectRatio属性を参照先のsvg画像に設定することが可能だからです.

これはhtml等からsvg画像を読み込んだ際にアスペクト比を変更したくないと言ったことを示すもので,これ自体は自然な解釈です.

ですが,ここで問題が発生します.参照先のsvg要素のpreserveAspectRatio属性とimage要素のpreserveAspectRatio属性はどのように関わりあうのでしょうか?

preserveAspectRatioの優先順を指定する


この問題は「defer」値を使って制御することができます.
preserveAspectRatio属性の先頭に「defer」を追加すると,参照先のsvg画像の設定を優先するようになります.ここで参照先の画像がラスタ画像だった場合や,参照先にpreserveAspectRatio属性が見つからなかった場合はimage要素の設定が用いられるのです.

実際に試してみる


これはw3cの仕様での話で,実際にブラウザが対応しているかは判りません.ですので,実際にどこまで使えるかを試してみたくなります.そこで実際に試してみたのが下の表です.

列に参照しているsvgの設定内容を,行にimage要素の設定を並べ表としました.




その結果,次のことが判りました.
  • defer値が正しく動作しているのはfirefoxのみである.
    chromeでは読みこむ毎に結果が変化する.operaではそもそも動作しない.
つまり,仕様上はdeferが定義されているものの,現状は使い途がないことになります.
しかもchromeで動作が不安定というのは問題です.(実はこの他にもchromeではpreserveAspectRatio周りの動作が怪しい面があります.)

因みにsvgにサイズが指定されていない場合はどうなるの?


この問題に絡み,サイズが設定されていないsvg画像を読み込んだ際の動作について調べて見ました.svg画像を入手した際,時折サイズが未指定の場合があります.このsvg画像をimage要素で表示させてみると思うようにアスペクト比設定が反映されないのです.

これはimage要素によって定義された描画領域にsvg画像が自動的にリサイズされている為なのですが,この部分を詳しくチェックしてみたわけです.その結果「あらゆるアスペクト比設定が無効となる」 ことが判りました.

(なお,実際にはこの他にもviewBox属性のみを指定した場合やwidth・height属性の片方のみ定義した場合などの検証が考えられますが,svgの設定内容に不備があると制御できないことが確かめられただけでも十分でしょう)

結論


以上のことから,svg画像をimage要素から読み込む際は次のようにすると良いことが判りました.
  • svg画像にはサイズを設定する.
  • defer値は用いずにimage要素側でアスペクト比の制御設定は行う.
まぁ重箱の隅というやつで…

0 件のコメント:

コメントを投稿