CSSのoffsetプロパティで、楽しいパスアニメーションを作ろう

はてなブックマークへ投稿
115
Xへポスト
41
URLをコピー
共有

offsetプロパティは、パス上に要素を配置・移動させるCSSのプロパティです。animationプロパティやtransitionプロパティと組み合わせることで、手軽に一見複雑そうなアニメーションが作れます。

SVGやJavaScriptは詳しくないけど、複雑そうな動きのアニメーションを作ってみたい方、animationプロパティなどのおさらいをしておきたい方にオススメの記事です。

offsetプロパティについて

offsetプロパティは、任意のパス上に要素を配置・移動させる一括指定プロパティです。以下の5つのプロパティが指定可能です。プロパティの詳細については、MDNのドキュメントをご参照ください。

  • offset-path:要素を配置・移動させるためのパス。(MDN
  • offset-distanceoffset-path上で要素を配置する位置。(MDN
  • offset-rotateoffset-pathに沿って配置された要素の向き・角度。(MDN
  • offset-anchoroffset-pathに沿って配置・移動している要素の原点の位置。(MDN
  • offset-positionoffset-pathの初期位置。(MDN

本記事では、offset-pathプロパティの値に設定できるCSS関数のうちpath()関数を用いて、offsetプロパティの基本的な使い方からアニメーションの作例までを紹介します。

offsetプロパティの使い方

1. 動かしたい要素を用意

画像や文字、図形など動かす要素を用意します。

<div class="offsetElement"></div>

2.要素を配置・移動させるパスを用意

続いて、要素を配置したり移動させるためのSVGのパスを用意します。SVGの基本的な特徴や作成方法については、記事『SVGで始めるマイクロインタラクション入門』 で紹介しています。今回のデモは自由度の高いベクター画像作成ソフトから書き出す方法を使ってパスを用意しました。

▼用意した画像とパス 用意した要素とパス

出力したSVG画像の<path>タグに記述されているd属性の値をコピーし、offset-pathプロパティで指定するpath()関数にペーストします。

<svg xmlns="http://www.w3.org/2000/svg" width="560" height="240" viewBox="0 0 560 240">
  <!--▼d=""のところをコピー-->
  <path d="m151.363,24...(省略)..." fill="none" stroke="#156EF3" stroke-width="1"/>
</svg>
.offsetElement {
  /* ▼path()関数にペースト */
  offset-path: path("m151.363,24...(省略)...");
}

3.offset-distanceプロパティやoffset-rotateプロパティ等を使っていい感じのアニメーションを作る

パス上を始点から終点へと移動するアニメーションを作るため、アニメーション終わりのキーフレームにoffset-distance: 100%;を指定したキーフレーム(move)を用意しました。イージングはlinearを指定し、40秒で1周を無限(infinite)に行うようアニメーションを指定しています。

また、用意したGIF画像がパス上を横移動するような向きになってしまっていたので、offset-rotate90degに回転させて向きを調整し、autoでパスの方向にしたがって角度を変えるようにしています。

▼CSS(一部省略しています)

.offsetElement {
  offset-path: path("m151.363,24...(省略)...");
  offset-rotate: auto 90deg;
  animation: move 40s linear infinite;
}

@keyframes move {
  to {
    offset-distance: 100%;
  }
}

offset-distanceの値をアニメーションさせてメンダコを泳がせるデモ

注意:<path>タグである必要がある

ベクター画像作成ソフトから基本図形を使って用意したパスをそのまま書き出すと、<circle>タグや<polygon>タグなど図形を書くためのコードして出力されます。

path()関数として使うには<path>タグとして用意しなければならないので、一工夫する必要があります。

Tips:基本的な図形をSVGで書き出しする際に、<path>タグとして書き出す方法(illustratorを使用)

  1. 任意の基本図形を作成
  2. はさみツール(ショートカットキー:C)で一点をカットする
  3. 通常と同じくSVGで書き出し

はさみツールで基本図形をのパスをカット

上記は基本図形で作った正円ですが、はさみツールで一点をカットしたことで、<circle>タグではなく<path>タグとして書き出すことができました。

また、path()関数に記述したパスのサイズ・比率などは、SVGを手動で記述できる方を除き、後からCSSで楽に調整することはできません。実際に表示するサイズで用意しておくことをオススメします

基本図形そのままとはさみツールでカットして書き出した際の比較

offsetプロパティを使った作例の紹介

ここからは、offsetプロパティを使って遊んでみた作例の紹介をします。

遊園地の作例

中央の観覧車がゆっくりと回り、その背景でジェットコースターが走る作例です。観覧車の方には、ゴンドラをホバーするとゆらゆら揺れるアニメーションを追加しています。

ジェットコースターについては、前述のメンダコのアニメーションと作り方が同じなので省略しますが、観覧車についてはアニメーション作成にあたって、いくつかのポイントがあります。

  1. offset-pathプロパティに正円のパスを指定。Zコマンドを追加しパスを閉じる。
  2. sibling-index()関数でゴンドラの並び順を取得する。
  3. キーフレームrotate-gondolafromで、各ゴンドラの並び順に応じて、offset-distance0%から10%ずつ加算して配置。
  4. キーフレームrotate-gondolatoに、キーフレームのfromで設定したoffset-distanceの値に100%を足して、100%を超えた値を指定。
  5. offset-rotateプロパティに0degを指定し、ゴンドラの向きを固定。
  6. translate: 0 20px;で位置を調整。

ポイント1つ目についての補足ですが、SVGを記述するコードに、Zコマンド(または小文字のzコマンド)というものがあります。SVGのパスは、座標に点を打つコマンド等を記述してパスを作っていきますが、Zzコマンドは現在の点とパスの始点を結合させる役割をします。

Zzコマンドはパラメーターを持たないので、大文字でも小文字でも同じ効果があります。

パスを閉じた形にすると、offset-distanceプロパティに100%を超えた値が指定できるため、今回はd属性の末尾の点にZコマンドを追加することで、終点と始点を繋げてパスを閉じました。

ゴンドラの並び順を取得するためにsibling-index()関数を使用しています。詳しく知りたい方は『CSSでスタッガーアニメーションがつくれる! sibling-index() / sibling-count()の活用アイデア』をご確認ください。

また、遊び要素としてゴンドラをホバーすると揺れるようなアニメーションを追加しました。アニメーションを綺麗に見せるためゴンドラのSVG画像にラッパー要素(div.gondola)を追加し、ラッパー要素をアニメーションさせています。アニメーションの詳細については、ソースコードをご覧ください。

▼HTML(一部省略しています)

<div class="ferrisWheel">
  <div class="ferrisWheel_gondola">
    <div class="gondola">
      <svg width="40" height="40" viewBox="0 0 40 40">
        <use href="./images/amusementPark/ferriswheel_gondola.svg#gondola"/>
      </svg>
    </div>
  </div>
  <!-- 一部省略。合計で10台のゴンドラを配置しています。 -->

  <span class="ferrisWheel_wheel"></span>
  <span class="ferrisWheel_frame"></span>
</div>

▼CSS(一部省略しています)

.ferrisWheel_gondola {
  position: absolute;
  width: 40px;
  height: 40px;
  translate: 0 20px;
  fill: hsl(
    calc(15deg + (sibling-index() - 1) * 36deg),
    100%,
    80%
  ); /* 並び順に応じて色相をずらし、レインボーにする */
  offset-path: path("M100,0 A100,100 0 1,1 100,200 A100,100 0 1,1 100,0 Z");
  offset-rotate: 0deg;
  animation: rotate-gondola 40s linear infinite;
}

@keyframes rotate-gondola {
  from {
    offset-distance: calc(10% * (sibling-index() - 1)); /* 0% 10% 20% ... 90% */
  }
  to {
    offset-distance: calc(100% + 10% * (sibling-index() - 1)); /* 100% 110% 120% ... 190% */
  }
}

コーヒー休憩の作例

コーヒーから湯気のように文字が立ち昇るアニメーションの作例です。

offset-distanceで渦巻き状のパスを移動する動きに合わせて、透明度とスケールを変えることで湯気っぽさが出るようなアニメーションを作成しました。一文字ずつ<span>要素で文字を囲み、animation-delay0.1sずつずらした値を指定することで、文字が繋がって動いて見えるようにしています。

▼HTML

<div class="coffee">
  <div class="coffee_text">
    <span>L</span>
    <span>e</span>
    <span>t'</span>
    <span>s</span>
    <span></span>
    <span>T</span>
    <span>a</span>
    <span>k</span>
    <span>e</span>
    <span></span>
    <span>a</span>
    <span></span>
    <span>b</span>
    <span>r</span>
    <span>e</span>
    <span>a</span>
    <span>k</span>
  </div>

  <span class="coffee_cup"></span>
</div>

▼CSS(一部省略しています)

.coffee_text {
  > span {
    position: absolute;
    display: block;
    font-size: 16px;
    offset-path: path("m61.498,27...(省略)...");
    opacity: 0;
    animation:
      move-text 3.2s linear infinite,
      distort-text 3.2s linear infinite;
    animation-delay: calc(sibling-index() * 0.1s);
  }
}

@keyframes move-text {
  0% {
    offset-distance: 100%;
    opacity: 0;
  }
  10%, 90% {
    opacity: 1;
  }
  100% {
    offset-distance: 0;
    opacity: 0;
  }
}

@keyframes distort-text {
  45% {
    scale: 1 1;
  }
  65% {
    scale: 1 1.8;
  }
  85% {
    scale: 1 1;
  }
  100% {
    scale: 1 0.5;
  }
}

お花の作例

お花がハート型のパス上で順番に咲くアニメーションの作例です。

offset-distanceプロパティの値を一輪ずつずらして均等に配置し、animation-delayプロパティで一輪ごとに0.05s遅延させています。華やかさを演出するため、透明度やスケール、回転などのプロパティを変化させるアニメーションにしています。

▼HTML(一部省略しています)

<div class="flower">
  <span class="flower_purple"></span>
  <span class="flower_sakura01"></span>
  <span class="flower_blue"></span>
  <!-- 以下省略。合計で30輪の花を配置しています。 -->
</div>

▼CSS(一部省略しています)

.flower {
  > span {
    offset-path: path("m98.754,196...(省略)...");
    animation: bloom 1.5s ease-out infinite;
    animation-delay: calc(sibling-index() * 0.05s); /* 一輪ごとに0.05sずらしてアニメーション */
    offset-distance: calc(100% * sibling-index() / sibling-count()); /* 一輪ずつずらして均等に配置 */
  }
}

@keyframes bloom {
  0% {
    transform: rotate(180deg) scale(0);
    opacity: 0;
  }

  30% {
    transform: rotate(0deg) scale(1);
    opacity: 1;
  }

  70% {
    transform: rotate(20deg) scale(1);
    opacity: 1;
  }

  100% {
    transform: rotate(180deg) scale(0.5);
    opacity: 0;
  }
}

おばけが浮遊する作例

おばけが浮遊しながら移動し、パス上の右端・左端に来た時はフリップして方向転換する作例です。ホバーすると移動を止めブルブル震えます。

offset-distanceプロパティの値を1%ずつずらして、パス上の何%が左右の位置に当たるのか確認し、パス上で右側にきた時(作例は16%64%)に、scale: -1 1;で左右反転させます。そして、左側にきた時(41%88%)にscale: 1 1;で画像の向きを元に戻してフリップする動きを作っています。

おばけのキーフレーム

おまけ要素として、ホバーした時にanimation-play-stateプロパティの値をrunningからpausedに切り替えて、その場に留まる挙動や震える動作等も追加しています。

手書き文字風アニメーションにペンを追従させ、書いている感を極めた例

SVGのマスクを使って、文字が書かれているようなアニメーションの表現は人気ですが、そこに万年筆を追従させることで、さらに書いている感を極めた作例です。

※アニメーション開始タイミングの制御にJavaScriptを使用しています。

文字を順に表示していくための<mask>タグとしてのパスと、ペンを動かす軌道としてのパスに同じ値を指定し、同時にアニメーションさせることで実現しています。

参考:SVGアニメーション、mask要素で手書き風テキスト。 - フーノページ

▼HTML(一部省略)

<div class="letters" data-wrapper-id="letters">
  <div class="letters_line">
    <svg xmlns="http://www.w3.org/2000/svg" width="300" height="270" viewBox="0 0 300 270">
      <g id="letters-svg-text">
        <path d="m50.281...(省略)..." />
        <!-- 一部省略。pathタグが続きます。 -->
      </g>

      <mask id="letters-svg-mask">
        <!-- 🌟万年筆のoffset-pathに指定するパスと同じ値です🌟-->
        <path d="m2.348,80...(省略)..." fill="none" stroke="white" stroke-width="5.5"/>
      </mask>
    </svg>
  </div>

  <span class="letters_pen"></span>
</div>

▼CSS(一部省略)

.letters_pen {
  position: absolute;
  display: block;
  width: 140px;
  height: 140px;
  translate: 50% -50%; /* ペン先を文字に合わせる */

  /* 🌟SVGの<mask>に指定するパスと同じ値です🌟 */
  offset-path: path("m2.348,80...(省略)...");
  offset-rotate: 0deg;
}

Appleのアニメーション風

Apple製品を最初に起動すると、画面に「hello」などの文字のアニメーションが再生されます。手書き文字風アニメーションと同じロジックで、Apple風アニメーションを実装できます。

対応ブラウザ

offsetプロパティは、Chrome 55(2016年12月)、Edge 79(2020年1月)、Safari 16.0(2022年9月)、Firefox 72(2020年1月)以上で利用可能です。

参照:Can I use…

まとめ

CSSのoffsetプロパティを使って、要素がパス上を動く一見複雑そうなアニメーションを簡単に作ることができました。必要に応じてSVGの学習を深掘りするのも良いでしょうし、JavaScriptと組み合わせてより複雑なアニメーションに挑戦するのも作りがいがありそうです。offsetプロパティを取り入れて、一味違うコンテンツを作るのはいかがでしょうか。

参考サイト

※この記事が公開されたのは3年前ですが、今月7月に内容をメンテナンスしています。

SNSでシェアしよう
シェアいただくと、サイト運営の励みになります!
はてなブックマークへ投稿
Xへポスト
URLをコピー
共有