WEB制作者向け無料テーマ「Arkhe」をリリースしました

【#2】SVGを極めたい!~ ビューポートとは何か・svgタグの描画領域・width,height,viewBox属性の挙動について ~

前回、SVGで簡単に図形を描画してみたのですが、そもそもこの図形が描画されている領域はどういうものなのでしょうか。

また、<svg>タグにはその描画領域を決めるための属性として、width、height属性と、viewBox属性を持つことができますが、これらの指定によって描画領域はどのように変化するのか。

全てのsvgグラフィックの元となる描画領域に関わることなので、丁寧に一つずつ確認していきたいと思います。

 

目次

SVGの描画領域について

とりあえず基本的なことは文章で理解しておきましょう。

SVG1.1仕様書の日本語訳版 - 「座標系, 変換, 単位」の項にて、以下のように説明されております。

メディアを問わず、 SVG キャンバスとは「 SVG 内容が描画される空間」を意味する。 キャンバスとは、どの方向にも無限の広がりを持つ空間である一方,描画についてはその有界な矩形領域に対し相対的になされるものである。 この有界な矩形領域を SVG ビューポート と呼ぶ。

つまり、図形が描画されている領域のことは「SVGビューポート」と呼ぶそうです。

下のCodePenは前回のメモで直線の描画を試した際のものですが、こちらにおける灰色のエリアのことです。

See the Pen SVG03-直線 by ddryo (@ddryo-the-encoder) on CodePen.

SVGビューポートの大きさ

SVGビューポートの大きさががどのように決定されるかについては、以下のように述べられています。

最も外側の svg 要素 の width 属性は、次の3条件が満たされる場合を除き,ビューポートの幅を確立する:

  • SVG 内容が( XHTMLの object 要素など)参照により埋めこまれる別個のリソースであるか,他の文書にインラインに埋めこまれており、
  • かつ, SVG 内容を参照している要素または包含している文書が CSS もしくは XSL によってスタイル付けされており、
  • かつ,ビューポートの幅を決めるのに十分な情報を持つ CSS 互換な位置決めプロパティが, SVG 内容を参照している要素(例えば object 要素)または包含している文書の 最も外側の svg 要素 に対して指定されている。

引用元:7.2 - 初期ビューポート

height属性についても同様に説明されています。

つまりざっくりとですが、「基本的には(最も外側の)svgタグのwidthおよびheight属性の値によってSVGビューポートの大きさが決定されるが、位置決めプロパティ(position:absoluteやfixed)がsvgタグに指定されていればそっちが優先されるよ」という認識で良いかと思います。

SVGにおける長さの単位について

width および height 属性が 利用単位(単位識別子のないただの数値) で指定されている場合、その値の単位は "px" であるものと見なされます。

また、長さ単位識別子には 「em, ex, px, pt, pc, cm, mm, in, および 百分率を利用できる」と述べられています。

初期座標系

座標については以下のように述べられています。

SVG-UA は、 最も外側の svg 要素 に対し,初期の ビューポート座標系 と初期の 利用座標系 を二つの座標系が同値になるように定める。双方の座標系の原点はビューポートの原点に合わせられ、初期座標系の1単位はビューポートにおける1「画素」(すなわち CSS2 で定義される 1 px )に等しくされる。

引用元:7.3 - 初期座標系

どうやらSVGには「ビューポート座標系」と「利用座標系」の2種類の座標系があるようです。

利用座標系」とは、transformによる回転や変形、後述するviewBoxによって任意に座標変換され得る座標系のことです。

原点の位置とX軸・Y軸の方向

先ほどの引用文に続いて、以下のように述べられていました。

ほとんどの場合、初期ビューポート座標系は(したがって初期利用座標系も),その原点をビューポートの左上隅に, X 軸正方向を右向きに, Y 軸正方向を下向きに, テキストの描画は「正立」した状態になるようにされる。

図にすると下のようになります。

viewBox属性について

viewBox属性については以下のように紹介されている。

一連のグラフィックを特定のコンテナ要素にぴったり収まるように拡縮させたい場面は多々ある。 viewBox 属性は、そのような機能を提供する。

(中略)

viewBox 属性の値は、空白またはコンマ区切りの4個の数値のリスト <min-x>, <min-y>, <width>, <height> で記述され,要素により確立されるビューポートの境界に写像されるべき,利用空間における矩形を指定する。 写像は preserveAspectRatio 属性も考慮に入れて決定される。 viewBox 属性が要素に指定された場合、追加の変換は要素のすべての子孫にも適用される。

引用元:7-7.viewBox属性

おそらくこれだけではちんぷんかんぷんだと思うので、ポイントとして押さえておきたい点をいくつか説明していきます。

viewBoxはレスポンシブで使える

まずviewBox属性の用途としてはこれが一番大きいでしょう。

svgタグにwidth,height属性を指定せず、viewBox属性のみを指定した場合、親コンテンツ幅に合わせてSVGビューポートが広がり、そのSVGビューポートの幅と高さを、<width>値、<height>値としてコンテンツを描画します。

以下のCodePen内の正方形はいずれも座標 (0,0) に、一辺 50 の長さで描画したものです。

See the Pen SVG 06- viewBoxはレスポンシブ by ddryo (@ddryo-the-encoder) on CodePen.

viewBox属性の前半2つの値について

viewBox属性は「4個の数値のリスト<min-x>, <min-y>, <width>, <height> で記述され」と述べられている。

これら前半二つの<min-x><min-y>について先に説明しておきます。

min-という接頭辞の通り、これら前半2つの数値は「座標系の最小値」を定めるものです。そして「座標の最小値」とはSVGビューポートの左上隅の値のことなので、SVGビューポートの左上隅の座標を指定するものになります。

実際の挙動を確認した方が分かりやすいかと思います。

以下のCodePenでの赤点は座標(0,0)の点を示しており、青点は(-50,-50)、緑点は (450,150)を示したものです。(いずれも半径は10)

See the Pen SVG07-viewBoxのminXとminY by ddryo (@ddryo-the-encoder) on CodePen.

viewBox="-50 -50 500 200"とすることで、以下のようなSVGビューポートになっていることがわかります。

viewBox属性はSVGビューポートに関する指定に影響しない。

SVGビューポートに関する指定(width,height属性)がある場合、viewBoxはそれらに影響しません。

つまり、widthやheight属性によって大きさが指定されている場合は、SVGビューポートはその大きさを維持したまま、viewBoxで指定された数値で利用座標の座標変換を行います。

実際の様子を見るのが早いかと思います。

See the Pen SVG08-ビューポート固定時のviewBoxの挙動 by ddryo (@ddryo-the-encoder) on CodePen.

preserveAspectRatio属性について

さて、先ほどのCodePenの後半4つの描画について、なぜこうなるのかよく分からない人も多いかと思います。

実は、svgタグにはpreserveAspectRatio属性というものを指定することができ、これの指定によって描画結果は変わります。

preserveAspectRatio属性がとれる値は、

xMidYMid(デフォルト)、xMinYMin、xMidYMin、xMaxYMin、xMinYMid、xMaxYMid、xMinYMax、xMidYMax、xMaxYMax、none

の10通り。(詳細は 7.8 preserveAspectRatio 属性

このうち、none以外は全て、均等な(比率を保った)拡縮を強制して座標変換を行います。

デフォルト値 xMidYMid の挙動

何も指定していない時はデフォルトでxMidYMidが指定されます。

xMidYMidというのは、

  • 均等な拡縮を強制する。
  • 要素の viewBox の X の中央値をビューポートの X の中央値に揃える。
  • 要素の viewBox の Y の中央値をビューポートの Y の中央値に揃える。

という指定になります。

例えば、先ほどCodePen中の「widthだけ半分の値」の場合を考えてみます。

400×200(比率 2:1)のSVGビューポートに対して、viewBoxの指定を200×200(比率 1:1)としても、比率は2:1のままで調整されるようになっています。

この時、比率2:1で調節すると、「400×200」もしくは「200×100」ですが、大きい方に合わせた「400×200」の大きさで座標変換されるようです。

しかし、xMidYMidのデフォルト指定により、ビューポートの中心にくる座標は、viewBoxの座標(利用座標系)の中心なので、座標(200,50)が中心として描画されます。

 

CodePenの解説図

先ほどのCodePenの各パターンの説明図をざっくり書いておきます。

ポイントは既に述べた通り、 preserveAspectRatio属性のデフォルト値によって比率が保たれ、かつ、SVGビューポートの中心にviewBoxの中心座標がくることです。

viwBoxの値がビューポートの倍の時(width="400" height="200" ViewBox="0 0 800 400")


viwBoxの値がビューポートの半分の時(width="400" height="200" ViewBox="0 0 200 100")


viwBoxの値がビューポートの 倍、かつ最小座標を指定した時
(width="400" height="200" ViewBox="-50 -50 800 400")

この時、利用座標の中心は(425,225)です。


widthだけ半分の時(width="400" height="200" ViewBox="0 0 200 200")

 この時、比率が保たれ 幅400 × 高さ200、中心が(100,100)の利用座標となる


heightだけ半分の時(width="400" height="200" ViewBox="0 0 400 100")

 この時、比率が保たれ 幅400 × 高さ200、中心が(200,50)の利用座標となる


widthだけ倍の時(width="400" height="200" ViewBox="0 0 800 200")

この時、比率が保たれ幅800 × 高さ400、 中心が(400,100)の利用座標となる


heightだけ倍の時(width="400" height="200" ViewBox="0 0 400 400")

この時、比率が保たれ 幅800 × 高さ400、 中心が(200,200)の利用座標となる

デフォルト値以外を指定した時の挙動を比較してみる

最後に、以下の3つの値を指定した場合の挙動の違いを比較してみます。

  • デフォルト値(xMidYMid)
  • xMinYMin
  • none

See the Pen SVG09-preserveAspectRatioによる違い by ddryo (@ddryo-the-encoder) on CodePen.

noneを指定した時のみ比率が歪み、viewBoxに指定した通りの幅と高さで座標変換されます。

おわりに

お疲れ様でした。

viewBox属性についてはなかなか複雑なので、今まで誤解していた部分もあったのですが、一つずつ確認していくことで理解を深めることができました。

実はこのviewBox属性、svgタグ以外のいくつかのタグにも指定することができます。それらに関しても全て理解しようと思うと気が遠くなるので、ひとまず、これくらいの知識でよしとしておきます。笑

さて、次回はいよいよpathについて勉強していこうとおもいます!

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメント一覧 (1件)

  • preserveAspectRatioについて詳しく解説している記事が見つからず困っていました!
    素晴らしい記事をありがとうございます!

目次