CSSでSVGアニメーションにアプローチする方法
公開: 2022-03-11アニメーションはウェブのいたるところにあります。 インターネットの初期のウェブサイトを悩ませていた点滅するGIF画像とは異なり、今日のアニメーションはより繊細で上品です。 デザイナーとフロントエンドスペシャリストは、これらを使用してWebサイトをより洗練されたものに見せ、ユーザーエクスペリエンスを向上させ、重要な要素に注意を促し、情報を伝えます。
Web開発者は、SVGとCSSの機能を組み合わせて、外部ライブラリを使用せずにアニメーションを作成できるというメリットがあります。 このSVGアニメーションチュートリアルは、実際のプロジェクト用にカスタムアニメーションを作成する方法を示しています。
CSSを使用したSVGアニメーション:コアコンセプト
CSSを使用してSVGをアニメーション化する前に、開発者はSVGが内部でどのように機能するかを理解する必要があります。 幸い、これはHTMLに似ています。SVG要素をXML構文で定義し、HTMLのようにCSSでスタイルを設定します。
SVG要素は、グラフィックを描画するために意図的に作成されています。 <rect>を使用して長方形を描画したり、 <circle>を使用して円を描画したりできます。—SVGは<ellipse> 、 <line> 、 <polyline> 、 <polygon> 、および<path>も定義します。
注: SVG要素の完全なリストには、同期マルチメディア統合言語(SMIL)を使用してアニメーションを作成できる<animate>も含まれています。 ただし、その将来は不確実であり、Chromiumチームは、可能な限りSVGをアニメーション化するためにCSSまたはJavaScriptベースのアプローチを使用することを推奨しています。
使用可能な属性は要素によって異なるため、 <rect>にはwidthとheightの属性がありますが、 <circle>要素には半径を定義するr属性があります。
ほとんどのHTML要素は子を持つことができますが、ほとんどのSVG要素は子を持つことができません。 1つの例外は、グループ要素<g>です。これは、CSSスタイルと変換を複数の要素に一度に適用するために使用できます。
<svg>要素とその属性
HTMLとSVGのもう1つの重要な違いは、特に特定の外部<svg>要素のviewBox属性を介して要素を配置する方法です。 その値は、空白またはコンマで区切られた4つの数値( min-x 、 min-y 、 width 、およびheight )で構成されます。 これらを合わせて、ブラウザにレンダリングするSVG図面の量を指定します。 その領域は、 <svg>要素のwidth属性とheight属性で定義されているように、ビューポートの境界に合うようにスケーリングされます。
レターボックス化に関しては、ビューポートのwidthとheightの属性の比率は、実際には、 viewBox属性のwidthとheightの部分の比率とは異なる場合があります。
デフォルトでは、SVGキャンバスのアスペクト比は、指定されたよりも大きいviewBoxを犠牲にして保持されるため、ビューポート内でレターボックス化されたレンダリングが小さくなります。 ただし、 preserveAspectRatio属性を使用して別の動作を指定できます。
これにより、画像を分離して描画し、コンテキストやレンダリングサイズに関係なく、すべての要素が正しく配置されることを確信できます。
SVG画像は手動でコーディングできますが、より複雑な画像にはベクターグラフィックプログラムが必要になる場合があります(SVGアニメーションチュートリアルでは両方の手法を示しています)。 私が選んだエディターはAffinityDesignerですが、どのエディターもここで説明する簡単な操作に十分な機能を提供する必要があります。
CSSトランジションとアニメーション
CSSトランジションを使用すると、プロパティの変更の速度と期間を定義できます。 開始値から終了値に瞬時にジャンプする代わりに、マウスでSVG円にカーソルを合わせると、SVG円の色が変わるこの例のように、値がスムーズに遷移します。
CodePenのFilipDefar(@dabrorius)によるペン遷移の例を参照してください。
トランジションプロパティを使用してトランジションを定義できます。 transitionするプロパティの名前、トランジションの期間、トランジションタイミング関数(イージング関数とも呼ばれます)、およびエフェクトが開始するまでの遅延の長さを受け入れます。 :
/* property name | duration | easing function | delay */ transition: margin-right 4s ease-in-out 1s;複数のCSSプロパティの遷移を定義できます。各プロパティは、個別の遷移値を持つことができます。 ただし、このアプローチには2つの明らかな制限があります。
最初の制限は、プロパティ値が変更されると遷移が自動的にトリガーされることです。 これは、一部のユースケースでは不便です。 たとえば、無限にループするアニメーションを作成することはできません。
2番目の制限は、遷移には常に初期状態と最終状態の2つのステップがあることです。 アニメーションの長さを延長することはできますが、異なるキーフレームを追加することはできません。
これが、CSSアニメーションというより強力な概念が存在する理由です。 CSSアニメーションを使用すると、複数のキーフレームと無限ループを持つことができます。
CodePenのFilipDefar(@dabrorius)によるペンアニメーションの例を参照してください。
複数のキーフレームでCSSプロパティをアニメーション化するには、最初に@keyframes -ruleを使用してキーフレームを定義する必要があります。 キーフレームのタイミングは、相対的な単位(パーセンテージ)で定義されます。これは、この時点では、アニメーションの継続時間がまだ定義されていないためです。 各キーフレームは、その時点での1つ以上のCSSプロパティの値を記述します。 CSSアニメーションは、キーフレーム間のスムーズな移行を保証します。
animationプロパティを使用して、記述されたキーフレームを持つアニメーションを目的の要素に適用します。 transitionプロパティと同様に、期間、イージング関数、および遅延を受け入れます。
唯一の違いは、最初のパラメーターがプロパティ名ではなく@keyframes名であることです。
/* @keyframes name | duration | easing-function | delay */ animation: my-sliding-animation 3s linear 1s;ハンバーガーメニューの切り替えをアニメーション化する
SVGのアニメーション化がどのように機能するかについての基本的な理解ができたので、古典的なアニメーションの作成を開始できます。これは、「ハンバーガー」アイコンと閉じるボタン(「X」)の間をスムーズに切り替えるメニュートグルです。
CodePenのFilipDefar(@dabrorius)によるペンハンバーガーを参照してください。
これは微妙ですが価値のあるアニメーションです。 アイコンを使用してメニューを閉じることができることをユーザーの注意を引き付けます。
3行のSVG要素を作成することからデモを開始します。
<svg class="hamburger"> <line x1="0" y1="50%" x2="100%" y2="50%" class="hamburger__bar hamburger__bar--top" /> <line x1="0" y1="50%" x2="100%" y2="50%" class="hamburger__bar hamburger__bar--mid" /> <line x1="0" y1="50%" x2="100%" y2="50%" class="hamburger__bar hamburger__bar--bot" /> </svg> 各行には2セットの属性があります。 x1とy1は線の始点の座標を表し、 x2とy2は線の終点の座標を表します。 相対的な単位を使用して位置を設定しました。 これは、画像のコンテンツが含まれているSVG要素に合うようにサイズ変更されるようにする簡単な方法です。 この場合、このアプローチは機能しますが、大きな欠点が1つあります。このように配置された要素のアスペクト比を維持できないことです。 そのためには、 <svg>要素のviewBox属性を使用する必要があります。
CSSクラスをSVG要素に適用したことに注意してください。 CSSを介して変更できるプロパティはたくさんあるので、SVG要素にいくつかの基本的なスタイルを適用してみましょう。
<svg>要素のサイズを設定し、カーソルの種類を変更してクリック可能であることを示します。 ただし、線の色と太さを設定するには、 strokeプロパティとstroke-widthプロパティを使用します。 colorやborderを使用することを期待したかもしれませんが、 <svg>自体とは異なり、SVGサブ要素はHTML要素ではないため、多くの場合、異なるプロパティ名があります。
.hamburger { width: 62px; height: 62px; cursor: pointer; } .hamburger__bar { stroke: white; stroke-width: 10%; } この時点でレンダリングすると、3つの線すべてが同じサイズと位置にあり、互いに完全に重なっていることがわかります。 残念ながら、CSSを使用して開始位置と終了位置を個別に変更することはできませんが、要素全体を移動することはできます。 transform CSSプロパティを使用して上部と下部のバーを移動してみましょう。
.hamburger__bar--top { transform: translateY(-40%); } .hamburger__bar--bot { transform: translateY(40%); }Y軸上でバーを動かすと、見栄えの良いハンバーガーになります。
次に、2番目の状態である閉じるボタンをコーディングします。 2つの状態を切り替えるには、SVG要素に適用される.is-openedクラスに依存します。 結果をよりアクセスしやすくするために、SVGを<button>要素でラップし、そのレベルでのクリックを処理しましょう。
クラスの追加と削除のプロセスは、単純なJavaScriptスニペットによって処理されます。
const hamburger = document.querySelector("button"); hamburger.addEventListener("click", () => { hamburger.classList.toggle("is-opened"); }); Xを作成するために、ハンバーガーバーに別のtransformプロパティを適用できます。 新しいtransformプロパティは古い変換プロパティを上書きするため、開始点は3つのバーの元の共有位置になります。
そこから、上部のバーを中心を中心に時計回りに45度回転し、下部のバーを反時計回りに45度回転させることができます。 Xの中心の後ろに隠れるように十分に狭くなるまで、中央のバーを水平方向に縮小できます。
.is-opened .hamburger__bar--top { transform: rotate(45deg); } .is-opened .hamburger__bar--mid { transform: scaleX(0.1); } .is-opened .hamburger__bar--bot { transform: rotate(-45deg); } デフォルトでは、SVG要素のtransform-originプロパティは通常0,0です。 これは、バーがビューポートの左上隅を中心に回転することを意味しますが、中央を中心に回転する必要があります。 これを修正するには、 transform-originプロパティを.hamburger__barクラスのcenterに設定しましょう。

transitionを使用したCSSプロパティのアニメーション
transition CSSプロパティは、CSSプロパティの2つの異なる状態間をスムーズに遷移するようにブラウザに指示します。 ここでは、バーの位置、方向、およびスケールを指定するtransformプロパティへの変更をアニメーション化します。
また、 transition-durationプロパティを使用して、遷移の期間を制御することもできます。 アニメーションをきびきびと見せるために、0.3秒の短い時間を設定します。
.hamburger__bar { transition-property: transform; transition-duration: 0.3s; ... }必要なJavaScriptの唯一の部分は、アイコンの状態を切り替え可能にするビットです。
const hamburger = document.querySelector("button"); hamburger.addEventListener("click", () => { hamburger.classList.toggle("is-opened"); }); ここでは、 querySelector()を使用して.muteクラスで外部SVG要素を選択します。 次に、クリックイベントリスナーを追加します。 クリックイベントがトリガーされると、階層のより深い部分ではなく、 <svg>自体でのみ.is-activeクラスを切り替えます。 CSSアニメーションを.is-activeクラスの要素にのみ適用するようにしたため、このクラスを切り替えると、アニメーションがアクティブ化および非アクティブ化されます。
最後の仕上げとして、HTML本文をフレックスコンテナに変換します。これにより、アイコンを水平方向と垂直方向の中央に配置できます。 また、背景色を非常に濃い灰色に更新し、アイコンの色を白に更新して、洗練された「ダークモード」のルックアンドフィールを実現します。
body { display: flex; justify-content: center; align-items: center; background-color: #222; height: 100vh; }これにより、いくつかの基本的なCSSと短いJavaScriptスニペットを使用して、完全に機能するアニメーションボタンを作成しました。 さまざまなアニメーションを作成するために適用した変換を簡単に変更できます。 読者は、CodePen(洗練するための追加のCSSが少し含まれています)をフォークするだけで、創造性を発揮できます。
外部エディターからのSVGデータの操作
ハンバーガーメニューはとてもシンプルです。 もっと複雑なものを作りたい場合はどうなりますか? ここで、SVGを手動でコーディングすることが難しくなり、ベクターグラフィックス編集ソフトウェアが役立ちます。
2番目のSVGアニメーションは、ヘッドフォンアイコンを表示するミュートボタンです。 音楽がアクティブになると、アイコンが脈動して踊ります。 ミュートすると、アイコンに取り消し線が引かれます。
CodePenのペンミュートボタン-5--FilipDefar(@dabrorius)による赤い取り消し線を参照してください。
アイコンの描画はこのチュートリアル(およびおそらくあなたの仕事の説明)の範囲外であるため、事前に描画されたSVGアイコンから始めます。 また、ハンバーガーメニューの例と同じbodyスタイリングが必要になります。
SVGコードを操作する前に、SVGコードをクリーンアップすることをお勧めします。 これは、オープンソースのNode.jsベースのSVGオプティマイザーツールであるsvgoを使用して行うことができます。 これにより、不要な要素が削除され、コードを手動で編集しやすくなります。これは、クラスを追加してさまざまな要素を組み合わせるために行う必要があります。
画像編集ソフトウェアで作成されたSVGアイコンは、相対的な単位を使用する可能性は低いです。 さらに、アイコンを含むSVG要素のアスペクト比に関係なく、アイコンのアスペクト比が維持されるようにする必要があります。 このレベルの制御を可能にするために、 viewBox属性を使用します。
viewBoxを使いやすい値に設定できるように、SVGのサイズを変更することをお勧めします。 この場合、100x100ピクセルのviewBoxに変換しました。
アイコンが中央に配置され、適切なサイズになっていることを確認しましょう。 muteクラスをベースSVG要素に適用してから、次のCSSスタイルを追加します。
.mute { fill: white; width: 80px; height: 70px; cursor: pointer; } ここでは、アニメーションの回転中にクリッピングが発生しないように、 widthはheightよりもわずかに大きくなっています。
私たちのSVGアニメーションの出発点
クリーンになったSVGには、3つの<path>要素を含む単一の<g>要素が含まれています。
パス要素を使用すると、線、曲線、および円弧を描画できます。 パスは、形状の描画方法を説明する一連のコマンドで説明されます。 アイコンは接続されていない3つの形状で構成されているため、それらを説明するための3つのパスがあります。
g SVG要素は、他のSVG要素をグループ化するために使用されるコンテナーです。 これを使用して、3つのパスすべてに脈動とダンスの変換を同時に適用します。
<svg class="mute" viewBox="0 0 100 100"> <g> <path d="M92.6,50.075C92.213,26.775 73.25,7.938 50,7.938C26.75,7.938 7.775,26.775 7.388,50.075C3.112,51.363 -0.013,55.425 -0.013,60.25L-0.013,72.7C-0.013,78.55 4.575,83.3 10.238,83.3L18.363,83.3L18.363,51.6C18.4,51.338 18.438,51.075 18.438,50.813C18.438,33.275 32.6,19 50,19C67.4,19 81.563,33.275 81.563,50.813C81.563,51.088 81.6,51.338 81.638,51.6L81.638,83.313L89.763,83.313C95.413,83.313 100.013,78.563 100.013,72.713L100.013,60.263C100,55.438 96.875,51.362 92.6,50.075Z" /> <path d="M70.538,54.088L70.538,79.588C70.538,81.625 72.188,83.275 74.225,83.275L74.225,83.325L78.662,83.325L78.662,50.4L74.225,50.4C72.213,50.4 70.538,52.063 70.538,54.088Z" /> <path d="M25.75,50.4L21.313,50.4L21.313,83.325L25.75,83.325L25.75,83.275C27.788,83.275 29.438,81.625 29.438,79.588L29.438,54.088C29.45,52.063 27.775,50.4 25.75,50.4Z" /> </g> </svg> ヘッドホンを脈動させて踊らせるには、 transitionだけでは不十分です。 これは、キーフレームを必要とするほど複雑な例です。
この場合、開始キーフレームと終了キーフレーム(アニメーションのそれぞれ0%と100%)は、わずかに縮小されたヘッドフォンアイコンを使用します。 アニメーションの最初の40%では、画像をわずかに拡大し、5度傾けます。 次に、アニメーションの次の40%で、アニメーションを0.9倍に縮小し、反対側に5度回転させます。 最後に、アニメーションの最後の20%で、アイコン変換はスムーズにループするために同じ初期パラメーターに戻ります。
@keyframes pulse { 0% { transform: scale(0.9); } 40% { transform: scale(1) rotate(5deg); } 80% { transform: scale(1) rotate(-5deg); } 100% { transform: scale(0.9) rotate(0); } }CSSアニメーションの最適化
キーフレームがどのように機能するかを示すために、キーフレームCSSを必要以上に冗長なままにしました。 短縮する方法は3つあります。
100%キーフレームはtransformリスト全体を設定するため、 rotate()を完全に省略すると、その値はデフォルトで0になります。
100% { transform: scale(0.9); } 次に、アニメーションをループしているため、 0%と100%のキーフレームを一致させる必要があることがわかります。 同じCSSルールでそれらを定義することにより、アニメーションループでこの共有ポイントを変更する場合に、両方を変更することを覚えておく必要はありません。
0%, 100% { transform: scale(0.9); } 最後に、すぐにtransform: scale(0.9);を適用します。 mute__headphonesクラスに追加します。そうする場合、開始キーフレームと終了キーフレームを定義する必要はまったくありません。 デフォルトでは、 mute__headphonesで使用される静的スタイルになります。
アニメーションのキーフレームを定義したので、アニメーションを適用できます。 .mute__headphonesクラスを<g>要素に追加して、ヘッドフォンアイコンの3つの部分すべてに影響を与えるようにします。 まず、アイコンを中心の周りで回転させたいので、もう一度transform-originをcenterに設定します。 また、サイズが最初のアニメーションキーフレームと一致するようにスケーリングします。 この手順を実行しないと、静的な「ミュート」アイコンからアニメーション化されたアイコンに切り替えると、常にサイズが突然大きくなります。 (どちらの方法でも、スケールをミュートに戻すと、スケールが0.9倍よりも大きいときにユーザーがクリックすると、スケールがジャンプし、回転も発生する可能性があります。CSSだけでは、その効果についてはあまりできません。)
animation CSSプロパティを使用してアニメーションを適用しますが、ハンバーガーメニューをアニメーション化したのと同様に、 .is-active親クラスが存在する場合に限ります。
.mute__headphones { transform-origin: center; transform: scale(0.9); } .is-active .mute__headphones { animation: pulse 2s infinite; }状態を切り替えるために必要なJavaScriptも、ハンバーガーメニューと同じパターンに従います。
const muteButton = document.querySelector(".mute"); muteButton.addEventListener("click", () => { muteButton.classList.toggle("is-active"); }); 次に追加するのは、アイコンが非アクティブのときに表示される取り消し線です。 これは単純な設計要素であるため、手動でコーディングできます。 これは、シンプルで合理的なviewBox値を持つことが役立つ場合です。 キャンバスのエッジが0と100にあることがわかっているので、ラインの開始位置と終了位置を簡単に計算できます。
<line x1="12" y1="12" x2="88" y2="88" class="mute__strikethrough" />サイズ変更と相対単位の使用
画像のサイズを変更する代わりに、相対的な単位を使用する場合があります。 これは、アイコンの上に単純なSVG行のみを追加しているため、この例に当てはまります。
実際のシナリオでは、いくつかの異なるソースからのより複雑なSVGコンテンツを組み合わせることができます。 この例で行ったように相対値を手動でハードコーディングすることはできないため、これらをすべて均一なサイズにすることが役立つ場合があります。
取り消し線の<line>要素にクラスを直接適用したため、CSSを介してスタイルを設定できます。 アイコンがアクティブなときに線が表示されないようにする必要があります。
.mute__strikethrough { stroke: red; opacity: 0.8; stroke-width: 12px; } .is-active .mute__strikethrough { opacity: 0; } オプションで、 .is-activeクラスをSVGに直接追加できます。 これにより、ページが読み込まれるとすぐにアニメーションが開始されるため、アイコンの初期状態を非アニメーション(ミュート)からアニメーション(非ミュート)に効果的に変更します。
CSSベースのSVGアニメーションは今後も続く
CSSアニメーション手法のほんの一部と、ビューポートの仕組みについて説明しました。 単純なアニメーションを単純に保つためにSVGコードを手作業で作成する方法を知ることは価値がありますが、外部エディターで作成されたグラフィックをいつどのように使用するかを知ることも重要です。 最新のブラウザでは、組み込みの機能のみを使用して印象的なアニメーションを作成できますが、(非常に)複雑なユースケースの場合、開発者はGSAPやanime.jsなどのアニメーションライブラリを調べたいと思うかもしれません。
アニメーションは、贅沢なプロジェクトのために予約する必要はありません。 最新のCSSアニメーション技術を使用すると、クロスブラウザ互換のシンプルな方法で、魅力的で洗練されたさまざまなアニメーションを作成できます。
この記事のテクニカルレビューをしてくれたMikeZeballosに特に感謝します!
