SVG、グラデーションのアニメーション
①〜線形編。

〽️ベクトルそのものを動かす。 〽️spreadMethod。 〽️アニメーション実装。 〽️グラデーションを文字ごと/全体に。 〽️背景の影響大。





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

こんにちは、「ふ」です。
前回はSVGのグラデーションの構造についてお伝えしましたが、今回からはいよいよアニメーションさせていきましょう。

その①として、線形グラデーションがエンドレスに横に流れていく、というものを作ってみたいと思います。

当記事はグラデーションアニメーションの「実践編」という位置付けでお話ししていきます。SVGのグラデーションの基本については「準備編」である⬇︎の記事を参考にしてください。

SVGのグラデーションについて。

2021.10.23
カラーストップ/オフセットとは?

ベクトルそのものを動かす。


エンドレスにグラデーションが流れていく、その仕組みを考えます。

単純な2色のグラデーションで考えてみましょう。
SVGのグラデーションは、始点と終点を持った線分(ベクトル)で定義されるものでした。

カラーストップの配置されたベクトル自体を、オブジェクトの外側からもう一方の外側まで動かす。
この動きをループさせれば、グラデーションがエンドレスに移動している様子を表現できます。

ただそうしたとき、要素に対してグラデーションのベクトルが重なっていない部分は、どのような「塗り」が適用されるのでしょうか?
それを指定するのがspreadMethod属性です。

spreadMethod。


<linearGradient id = .... 「「1spreadMethod = ""」」 />

linear/radialGradientのspreadMethod属性は、グラデーションのベクトルの外側をどのように塗りつぶすかを指定します。

いま⬆︎の長方形に対し、中央にグラデーションのベクトルが配置されています。
長方形の両端にはグラデーションのベクトルが重なっていません。「グラデーションベクトルの外側」ということに成増。

初期値は「pad」。
直近のカラーストップの色で塗りつぶされます。

グラデーションベクトルの左側。直近のカラーストップは「濃いグレー」なので、同色で塗りつぶされます。右側は直近のカラーストップが「赤」なので、これまた同じ色で塗りつぶされます。

「エンドレスに流れるグラデーション」を考えたとき。
ベクトルの外側は単色で塗りつぶされることになるので、この初期値「pad」は使えそうもありません。

「repeat」。
ベクトルの外側が、同じグラデーションパターンで繰り返されます。

これを使って何かおもしろいことができそうですが、パターンの境界がくっきりと出てしまっています。
シームレスなグラデーションの実装には不向きですね。

「reflect」。
グラデーションベクトルの外側を同じパターンで繰り返すのですが、そのつどベクトルの向きを反転させながら並べられていきます。

これが使えそうだ。

グラデーションパターンを繰り返しつつ、シームレス。
この「spreadMethod = "reflect"」を使って、実装していきましょう。

アニメーション実装。


それではアニメーションを実装していきます。
イラレやVectornatorなどで長方形に線形グラデーションを施し、SVG形式で書き出します。

<svg viewBox="0 0 841.9 595.3"> <style type="text/css"> 「「3/* グラデーションを呼び出し、長方形の塗りに適用 */」」 「「4.st1」」 { fill:url(「「5#SVGID_1_」」); } </style> 「「3<!-- グラデーション定義 -->」」 <linearGradient id=「「5"SVGID_1_"」」 gradientUnits="userSpaceOnUse" x1="149.9" y1="297.6" x2="691.9" y2="297.6"> <stop offset="0.2654" style="stop-color:#353535"/> <stop offset="0.7335" style="stop-color:#CE1F13"/> </linearGradient> 「「3<!-- 長方形 -->」」 <rect x="149.9" y="112.3" class=「「4"st1" 」」width="542" height="370.7"/> </svg>

「準備編」のおさらい。
グラデーションを定義し、長方形を描画。
CSSでグラデーション定義を呼び出し、長方形の塗り(fill)に適用しています。

水平移動ということで、x1とx2の座標を同時に同じだけ動かします。
gradientの「x1」「x2」属性は、CSSで指定することができません。なので今回のアニメーションはSVGの<animate>要素を使って実装します。

<linearGradient>要素に対し、アニメーションに必要なコードを追加します。



<linearGradient id= "SVGID_1_" gradientUnits="userSpaceOnUse" 「「3<!-- ベクトルの外側をreflectで塗りつぶす -->」」 spreadMethod = "reflect" 「「1....①」」 x1="149.9" y1="297.6" x2="691.9" y2="297.6"> <animate attributeName = "x1" dur = "4s" from = "-100%" to = "100%" repeatCount = "indefinite"/> <animate attributeName = "x2" dur = "4s" from = "0%" to = "200%" repeatCount = "indefinite"/>「「1 ....②」」 <stop offset="0.2654" style="stop-color:#353535"/> <stop offset="0.7335" style="stop-color:#CE1F13"/> </linearGradient>

① さきほど紹介したspreadMethod属性を「reflect」に指定します。

② <animate>要素でベクトルの始点と終点に対し、アニメーションのタイミングとキーフレームを指定します。

・attributeName : アニメーションさせる属性
・dur : 継続時間
・from、to : 始めと終わりのキーフレームです。
・repeatCount : 繰り返し回数を指定します。

グラデーションベクトルの大きさが変わらないよう、始点は「-100〜100%」、終点は「0〜200%」へと移動させるようにしましょう。

結果⬆︎です。
エンドレスにグラデーションが動いているものの、カラーストップ間の距離が大きいような気がします。

画像をSVGで書き出したとき、gradientUnitsに「userSpaceOnUse」が指定されていたことが原因です。
x1とx2の距離は「100%」になるようにアニメーションを仕込んでいました。「userSpaceOnUse」の状態だと、x1、x2属性はviewBoxを基準に配置されます。
その結果、グラデーションベクトルの大きさは要素の大きさではなく、viewBoxの大きさになってしまっていたのでした。

「「3gradientUnits = "userSpaceOnUse"」」  ▼ 「「1gradientUnits = "objectBoundingBox"」」

<linearGradient>タグの中に記述されているgradientUnitsの指定を「objectBoundingBox」に変更してやりましょう。
そうすると、グラデーションベクトルの大きさが要素のバウンディングボックスの幅と等しく成増。

画像を作成したときのグラデーションの大きさで、アニメーションするようになりました。
なお、「objectBoundingBox」はgradientUnits属性の初期値なので、記述自体をそのまま削除しても同じ結果が得られます。

グラデーションを文字ごと/全体に。


先程のgradientUnitsの指定を利用すると、テキストのグラデーションを「1文字ごとに施す」/「全体に施す」の切り替えができます。

ベクターソフト上で、アウトライン化したテキスト⬆︎。まだ塗りは指定しておらず、初期値の#000です。
これをSVGで書き出して実験してみます。



<svg viewBox="0 0 841.9 595.3"> bb<path ...... /> bb<path ...... /> bb<path ...... /> bb..... </svg>

アウトライン化したテキストの部品がpathデータとして羅列されています。
ここに、先程のアニメーションの入った<linearGradient>要素を追加し、pathデータの塗りに適用します。

<svg viewBox="0 0 841.9 595.3"> 「「3<!-- グラデーション定義を追加 -->」」 <linearGradient 「「5id="SVGID_1_"」」 「「1gradientUnits="objectBoundingBox"」」 x1="149.9449" y1="297.6378" x2="691.9449" y2="297.6378" spreadMethod = "reflect"> <animate attributeName = "x1" dur = "4s" from = "-100%" to = "100%" repeatCount = "indefinite"/> <animate attributeName = "x2" dur = "4s" from = "0%" to = "200%" repeatCount = "indefinite"/> <stop offset="0.2654" style="stop-color:#353535"/> <stop offset="0.7335" style="stop-color:#CE1F13"/> </linearGradient> 「「3<!-- 要素をグループ化 -->」」 <g 「「5id = "moji"」」> bb<path ...... /> bb<path ...... /> bb<path ...... /> bb..... </g> 「「3<!-- グラデーションを塗りに適用 -->」」 <style> 「「5#moji」」 { fill:url(「「5#SVGID_1_」」); } </style> </svg>

アウトライン化したテキスト要素は、ベクターソフトから書き出したときにすでにグループ化されている場合もあります。そうでない場合には、<g> 〜 </g>で囲んでid名を付けましょう。
そうすることにより、各要素にグラデーションを一括で適用することができます。

結果⬆︎です。
gradientUnits属性を初期値の「objectBoundingBox」としているので、1文字単位でグラデーションが動いています。
それでは「userSpaceOnUse」に変更してみましょう。

「usersSpaceOnUse」にすると、グラデーションのベクトル座標はviewBoxを元に算出されます。
結果、テキスト全体を1つのグラデーションが移動するようになりました。

1つの属性値を書き換えるだけで、このような変化が楽しめます。
状況に応じて好きなほうを採用してくださいね。

背景の影響大。


今回SVGのグラデーションを動かすにあたっていくつか実験を行ってきたのですが、1つ気づいたこと。
グラデーションのアニメーションは、背景色によってまったく雰囲気が変わってくるという点です。

前のセクションで作ったアニメーションの背面に、カラーストップと同色の長方形を配置しました。
さっきの白バックのときとは雰囲気がガラリと変わります。
これは極端な例ですが、背景色も変化させて実験してみると、思わぬ発見があるかもしれません。

最後までお読みくださり、ありがとうございました。
今回はSVGの線形グラデーションを動かしてみましたが、こんどは円形グラデーションのアニメーションに挑戦してみたいと思います。
どんなものを作ろうか、今から楽しみです(← まだ考えていない)。完成次第、記事にしますのでお待ちください。

ではまた〜〜 ♫



HSL変換を使った配色や色指定。

2021.09.24
配色パターンを秒作。

CSSアニメーション、期末テスト。

2021.09.12
transform/transitionのスキル。

SVGでボタンアニメーション【Web Animations API】。

2020.12.19
event.targetからオブジェクトを動かす。











「ふ」です。

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