とほほのCSSモーションパス入門

目次

モーションパスとは

CSSのアニメーションを決められたパスに沿って動かす技術です。下記の仕様書で定義されています。

Chrome 46, Edge 79, Firefox 72, Safari 16.0 から利用可能です。

下記のプロパティが定義されています。

以前は motion-path, motion-distance などの名称でしたが offset-path, offset-distance などの名称に変更されました。

基本的なサンプル

offset-path で五角形のパスを定義し、offset-distance でパス上の距離を指定します。アニメーションでパス上の距離 0% から距離 100% までを移動させています。

CSS
.my-example-basic {
  .elem {
    font-size: 32px;
    offset-path: path("M15,50 L45,50 54,22 30,5 6,22Z");
    animation: my-animation 4s ease infinite;
  }
}
@keyframes my-animation {
  0%   { offset-distance: 0%; }
  100% { offset-distance: 100%; }
}
HTML
<div class="my-example-basic">
  <div class="elem">→</div>
</div>
表示

上記のサンプル表示では五角形が分かりやすいように背景に薄い五角形を描画しています。背景も含めたソースは下記になります。

CSS
.my-example-basic {
  position: relative;
  svg {
    position: absolute;
  }
  .elem {
    position: absolute;
    font-size: 24px;
    offset-path: path("M15,50 L45,50 54,22 30,5 6,22Z");
    animation: my-animation 4s ease infinite;
  }
}
@keyframes my-animation {
  0%   { offset-distance: 0%; }
  100% { offset-distance: 100%; }
}
HTML
<div class="my-example-basic">
  <svg>
    <path d="M15,50 L45,50 54,22 30,5 6,22Z" stroke="#ddd" fill="transparent" stroke-width="2" />
  </svg>
  <div class="elem">→</div>
</div>

パス指定(offset-path)

offset-path は移動体が進むべきパスを指定します。

基本形指定(<basic-shape>)

offset-path: path("M15,50 L45,50 54,22 30,5 6,22Z");
offset-path: circle(20px at 40px 40px);
offset-path: offset-path: ellipse(30px 20px at 30px 30px);
offset-path: rect(10px 50px 50px 10px);

放物線指定(ray())

offset-path には ray() 関数を指定することもできます。ray には放射線の意味があります。下記の例では、左下(bottom left)を起点として、上方を0度として時計方向に85度の方向(85deg)に、最も遠い枠線までの距離分(farthest-side)、枠線からははみ出さない程度(contain)に進む放物線をパスとしています。詳細は offset-path: ray() を参照してください。

CSS
.my-example-ray {
  height: 50px;
  width: 300px;
  border: 1px solid #ccc;
  .elem {
    height: 20px;
    width: 20px;
    background-color: #99f;
    offset-path: ray(85deg farthest-side contain at bottom left);
    animation: my-animation 4s ease infinite;
  }
}
HTML
<div class="my-example-ray">
  <div class="elem"></div>
</div>
表示

パス上の距離(offset-distance)

offset-distance はパス上の距離を長さ、またはパーセンテージで指定します。下記の例ではアニメーション開始時の距離を起点(左下)から 20%、終了時の距離を 80% に指定しています。

CSS
@keyframes my-animation-distance {
  0%   { offset-distance: 20%; }
  100% { offset-distance: 80%; }
}
表示

開始位置(offset-position)

offset-position はモーションパスの開始点が明示されていない時の開始位置を指定します。下記の例では ray() 関数で放物線は定義されていますが開始点は指定されていません。offset-position で開始点を左から 20px (left 20px)、下から 20px (bottom 20px) の位置に指定しています。

CSS
.my-example-position {
  width: 80px;
  height: 80px;
  border: 1px solid #ccc;
  .elem {
    width: 10px;
    height: 10px;
    background-color: #99f;
    offset-path: ray(45deg contain farthest-corner);
    offset-position: left 20px bottom 20px;
    animation: my-animation 1s ease infinite alternate;
  }
}
CSS
<div class="my-example-position">
  <div class="elem"></div>
</div>
表示

アンカー位置(offset-anchor)

offset-anchor は移動体のアンカー位置(パスに添わせる位置)を指定します。

CSS
.my-example-anchor {
  display: flex;
  .my-box {
    position: relative;
    width: 100px;
    height: 80px;
    .elem {
      width: 20px;
      height: 20px;
      background-color: #99f;
      text-align: center;
      offset-path: rect(30px 70px 70px 30px);
      offset-rotate: 0deg;
      animation: my-animation 6s ease infinite;
    }
  }
}
HTML
<div class="my-example-anchor">
  <div class="my-box">
    <svg>
      <rect x="30" y="30" width="40" height="40" stroke="#ddd" fill="transparent" stroke-width="2" />
    </svg>
    <div class="elem" style="offset-anchor: center center">A</div>
  </div>
  <div class="my-box">
    <svg>
      <rect x="30" y="30" width="40" height="40" stroke="#ddd" fill="transparent" stroke-width="2" />
    </svg>
    <div class="elem" style="offset-anchor: right bottom">B</div>
  </div>
</div>

ひとつめの移動体は中心(center center)をアンカー位置としていますが、ふたつめの移動体は右下(right bottom)をアンカー位置として移動しています。

表示
A
B

ローテート(offset-rotate)

offset-rotate は移動体の回転角度を指定します。

CSS
.my-example-rotate {
  display: flex;
  gap: 8px;
  .my-box {
    width: 100px;
    height: 100px;
    position: relative;
    .my-title {
      position: absolute;
    }
    svg {
      position: absolute;
    }
    .elem {
      width: 20px;
      height: 20px;
      background-color: #99f;
      text-align: center;
      offset-path: rect(30px 70px 70px 30px);
      animation: my-animation 6s ease infinite;
    }
  }
}
HTML
<div class="my-example-rotate">
  <div class="my-box">
    <div class="my-title">auto</div>
    <svg>
      <rect x="30" y="30" width="40" height="40" stroke="#ddd" fill="transparent" stroke-width="2" />
    </svg>
    <div class="elem" style="offset-rotate: auto">A</div>
  </div>
  <div class="my-box">
    <div class="my-title">reverse</div>
    <svg>
      <rect x="30" y="30" width="40" height="40" stroke="#ddd" fill="transparent" stroke-width="2" />
    </svg>
    <div class="elem" style="offset-rotate: reverse">A</div>
  </div>
  <div class="my-box">
    <div class="my-title">auto 90deg</div>
    <svg>
      <rect x="30" y="30" width="40" height="40" stroke="#ddd" fill="transparent" stroke-width="2" />
    </svg>
    <div class="elem" style="offset-rotate: auto 90deg">A</div>
  </div>
  <div class="my-box">
    <div class="my-title">45deg</div>
    <svg>
      <rect x="30" y="30" width="40" height="40" stroke="#ddd" fill="transparent" stroke-width="2" />
    </svg>
    <div class="elem" style="offset-rotate: 45deg">A</div>
  </div>
</div>

auto を指定すると通常の回転(右側が進行方向)が行われます。reverse を指定すると auto と逆の方向となります。auto 90deg を指定すると auto90deg を加えた角度になります。45deg を指定すると常に45度の角度となります。

表示
auto
A
reverse
A
auto 90deg
A
45deg
A

ショートハンド/一括指定(offset)

offsetoffset-path, offset-distance, offset-position, offset-anchor, offset-rotate のショートハンド(一括指定)プロパティです。

CSS
.elem {
    /* offset-path: rect(30px 70px 70px 30px); */
    /* offset-rotate: 0deg; */
    /* offset-anchor: bottom right; */
    offset: rect(30px 70px 70px 30px) 0deg / bottom right;
}