SVG要素のtransformについて。

〽️前後にかさなっている。 〽️領域はviewBox。 〽️originは左上。 〽️viewBoxに支配される。 〽️考慮すべきは4つ。





⬆︎SVGついてのまとめページ、CSSアニメーションの基本コーナーはこちら。

こんにちは、「ふ」です。
SVGをwebに取り入れてアニメーションさせると楽しいですよね ♪ でも、CSSを使ってSVG内の要素をtransformさせたとき、予想に反した動きになることが多々あります。

そもそも通常のHTML要素とSVG内の要素では、構造がかなり異なっているのがその理由です。

今回はSVG内要素の構造、またCSSでtransformさせた場合にどういった動きになるのか?を紹介していきます。 これらの仕組みさえ理解していれば、SVG要素をtransformさせるときに戸惑うこともなくなるでしょう。



完結編でもある。

また当記事は、4回に渡っての「transform-matrixシリーズ」の完結編にもあたります。
記事の下のほうにmatrixについてのリンクも貼ってありますので、参考にしてください。

前後にかさなっている。


SVG内の各要素は、どのような形で配置されているのでしょうか。
通常のHTML要素との違いも考えながらみていきましょう。

SVGではテキストデータをを扱うこともできますが、実際には画像目的で使うことがほとんどです。
すこし乱暴に言ってしまうと、SVG画像は図形データの集まりで構成されています。そして、個々の要素の配置方法はHTML要素の場合と大きく異なっています

先づHTMLの<body>に要素が並べられたときの構造を見てみましょう。

<body> 「「1bb<h1>・・・</h1> bb<img>・・・</img> bb<h2>・・・</h2> bb<p>・・・</p>」」 <body>

通常のHTML要素は、1枚の平面上に順番に並べられていきます。

で、次は<svg>タグ内の要素。

<svg viewBox = ・・・> 「「1bb<path d = ・・/> bb<path d = ・・/> bb<path d = ・・/>」」 </svg>

SVGタグ内の要素は、親のSVG領域(viewBox)に順に重ねられていく、という構造をとっています。
内部要素が前後に重なっている。これは、CGソフトの「レイヤー」と同じ要領です。

SVG画像、ぱっと見は1枚の画像のようでいて、実は子要素(オブジェクト)が前後に重なり合わせて構成されている。このことを覚えておいてください。




領域はviewBox。


SVGの各要素が所持している領域も、HTML要素と大きく違います。
2つを比較してみましょう。

HTML要素の場合、要素そのものとpaddingを含めた部分が「領域」です。座標空間を考えたときの原点(0,0)は左上に位置します。

ところがSVGに含まれている各要素の領域は、viewBox(親である<svg>に定義された座標空間)の範囲と成増。
全ての内部要素がviewBoxと同じ大きさの領域を持ち、前後に重ねられています。
座標空間の原点は要素の左上ではなく、領域の左上に位置します。

検証してみましょう。

element { transform:translateX(「「550%」」); }

translateXに指定した「%」値は、要素自身の領域に対する割合です。
例えば現在「50%」に指定しているのですが、「領域の幅:100px」の要素だと「50px」ということに成増。



HTML要素とSVG内要素のそれぞれをtrnaslateさせると、どうなるのか。

こちら⬆︎は、通常のhtml要素にtranslateX(50%)を指定したもの。

自身の領域の50%ぶん、左へと移動しているのがわかります。

そして、こっち⬆︎はSVGの子要素にtranslateX(50%)を掛けたものです。
〜HTML要素のときよりも明らかに移動量が多いですね。

これは、この子要素の領域がviewBoxの大きさになっているから。その50%の距離を移動しているのです。

要素の見た目は同じ大きさでも、HTML要素とSVGの子要素では、自身の持つ領域が違うということがわかります。

originは左上。


ここではtransform-origin(変形の基準点)において、SVGのオブジェクトと通常のHTML要素の違いについてお伝えします。

HTML要素の場合は、初期値が「center(要素の中心)」となっています。

SVGに含まれる要素のtransform-originのデフォルトは、座標の原点、つまり領域の左上に位置しています。

これについても大きく違う点ですね。



両方の要素にtransform:scale(拡大縮小)を施して、その違いを観察してみましょう。

#sample { animation:scale 1s alternate linear infinite; } @keyframes scale { bbto { 「「1transform:scale(1.5);」」 } bb}

HTML要素のtransform-originの初期値は「center」なので、中心を基準にアニメーションしています。

originを要素の左上に移動させてみましょう。

#sample { 「「1transform-origin:top left;」」 animation:scale 1s alternate linear infinite; }

左上を基準に拡大縮小するようになりました。

次はSVG領域の中にある長方形。
同じキーフレームのアニメーションを指定してみます。

#sample { animation:「「4scale」」 1s alternate linear infinite; }

transform-originが初期値「左上」なので、そこを基準に拡大していま ....
というか、ちょっと移動してしまっている!

SVG内要素のtransform-originは「左上」と言っても、要素自体の左上ではなく、領域の左上に位置しているのです。
transformを施すと領域全体が変形するため、要素自体の見た目は「拡大しつつ、右下に移動している」ようになりました。

真ん中ならいいのだが。

サンプルでは要素自体が、領域のど真ん中に位置しています。
もし要素の中心を基準に変形させたい場合は、「要素の中心 = 領域の中心」なので、

#sample { 「「1transform-origin:center;」」 }

とすれば良いでしょう。
.....しかしこれはラッキーなケースです。

要素は領域の中央に位置しているとは限りません。
たとえば、こんな⬆︎ところにある要素に対して、transform-origin(変形の基準)を的確にコントロールしたい場合。そのときは、要素の座標値を取得して算出するしかありません。

少し骨の折れる作業ではありますが、基準点指定のアイデアはこちら⬇︎の記事で紹介しています。

SVGアニメーション、 回転の中心を指定する。

2021.03.09
座標を取得して%変換。


viewBoxに支配される。


transform:matrixは、座標空間を操作することで要素を変形させます。

#sample { transform:matrix(1,0,0,1,「「10,0」」); }

matrixは6つの引数を持っていますが、5、6番目の引数は移動を指定します。実際の移動距離は親要素の座標空間に依存します。

HTML要素の場合。デフォルトの座標空間は「1目盛 = 1px」です。特に指定を行わない場合、これは全ての要素に共通します。

#sample { transform:matrix(1,0,0,1,「「1100,0」」); }

HTML要素に対し、transform-matrixで「x方向に100」の移動を指定しました。

親要素も「1目盛 = 1px」の座標空間を持っているので、結果100pxの移動が行われます。

しかし。SVG内部の要素にmatrix移動をかけた場合は、事情が違ってきます。
内部要素の直接の親は、<svg>要素です。<svg>要素の座標空間は「viewBox」で定義されているため、実際の移動距離は定義された座標に依存します。

座標定義の違うSVG画像で、matrixの動きを比較してみましょう。

<svg viewBox = 「「1"0 0 4 3"」」> <rect id = 「「5"rect1"」」 x = "25%" y = "33.33%" width = "50%" height = "33.33%"/> </svg>



viewBoxを「0 0 4 3」と定義したsvg領域に、長方形(#rect1)を配置しました。


ではもうひとつ。

<svg viewBox = 「「1"0 0 16 12"」」> <rect id = 「「5"rect2"」」 x = "25%" y = "33.33%" width = "50%" height = "33.33%"/> </svg>



もう1つは、viewBoxの分割量を「0 0 16 12」と細かくしました。
配置した長方形のid名は「rect2」とします。

その他の指定は1つめのSVGと全く同じです。web上の見た目も区別がつきません。

ここで2つの長方形を、transform:matrixで移動させてみます。

#rect1,rect2 { animation:ido 1.5s alternate infinite; } @keyframes ido { bbto { transform:matrix(1,0,0,1,「「11,0」」); bb} bb}

結果。



1つめのSVGです。長方形(#rect1)が移動し、viewBoxの端まで到達しています。



2つめのSVGにある長方形(#rect2)にも、まったく同じアニメーションを仕込みましたしかし!
ちょこっとしか移動していませんね。

これが、「viewBoxに支配されている」ということです。
transformに指定した値は、

transform:matrix(1,0,0,1,「「11,0」」);

でした。
5、6番目の引数が意味するのは、「x方向に『1』移動、y方向はそのまま」というものです。

1つめのSVGのviewBox定義は、「0 0 4 3」でした。
横4分割、縦3分割です。そうすると1目盛りの大きさは⬆︎のように、viewBox横幅の1/4の大きさです。
matrixで「x方向に『1』移動」とすると、このぶんだけ移動します。

2つめのSVG。
viewBox定義は「0 0 16 12」、横16分割、縦12分割です。
1目盛りはviewBox横幅の1/16しかありません。したがって「x方向に『1』移動」としても、ほんのちょびっとしか移動しなかったんですね💧

matrixで移動させる際は、viewBoxの定義に依存します。注意してください。

考慮すべきは4つ。


最後までお読みくださり、ありがとうございました。
これまで見てきたことを箇条書きにするならば、以下の4つ⬇︎。

① SVG内では各要素が前後に重ねられている。

② 領域はviewBoxと同じ範囲。

③ transform-originは(要素ではなく)領域の左上。

④ matrixでの移動量はviewBoxで定義された座標空間に依存する。

〜以上の点に配慮すれば、SVG内要素をtransformさせたときの「ハマりどころ」からは、すぐに脱出が可能です。どんどんtransformさせて、見ていて楽しいwebサイトを作ってくださいね。

扨扨(さてさて)、4回に渡ってお伝えしてきた「matrixシリーズ」も、これで完結です、お疲れ様でした。
SVGアニメーション、次回からは通常のチュートリアルを発信再開。紹介したいネタがたくさんあるので、覚悟しておいてください、ふふふ。

ではまた〜 ♪



transform:matrixを理解する。

2021.06.14
行列計算は必要なし。


transform:matrixの使い方①。

2021.06.24
基本的な変形をmatrixで行う。


transform:matrixの使い方② 〜要素の反転と基準点について。

2021.07.05
matrixにおける「基準点」の役割とは?


SVGとCSSで作る、吹き出しアニメーション。

2020.08.10
〽️ 吹き出しの形は自由自在。











「ふ」です。

swift、web、ガジェットなど。役立つ情報や観ていてたのしいページを書いていきたいと思います。