「トップページにもう少し動きが欲しい」——クライアントからのこの一言は、受託の制作現場でいちばんよく出てくる要望のひとつです。応えようとしてアニメーションライブラリを一つ足し、要素の座標を時間で動かすスクリプトを書く。デモではきれいに動きます。ところが数ヶ月後、ページの表示が体感で重くなり、スマホでカクつき、別の担当者がリニューアルで DOM をいじった途端にアニメーションが画面外へ飛んでいく。「動き」を足すたびに、保守コストとパフォーマンスの負債が静かに積み上がっていく。これは、動きの実装を JavaScript に寄せすぎていることが原因です。
要素を「ある決まった軌道(パス)に沿って動かす」だけなら、いまは CSS の offset-path でほぼ JavaScript なしに書けます。CSS-Tricks が 2026 年 6 月に整理した offset-path(CSS-Tricks Almanac) のとおり、この機能はブラウザに広く実装され、実務で使える段階に入りました。本記事では、受託で「軽くて壊れにくいモーション」を作る道具として offset-path をどう使うか、そしてどこで使うべきでないかを、制作の立場から具体的に整理します。
なぜ JavaScript での座標アニメーションが負債になるのか
要素を曲線に沿って動かすとき、JavaScript で実装すると、毎フレーム要素の transform や top/left を計算して書き換えることになります。これ自体は動きますが、受託案件では次の三つがあとで効いてきます。
ひとつは、メインスレッドの負荷です。スクロールやタップに反応して JS が座標を計算し続けると、その間ブラウザは他の処理(入力への反応など)を待たせます。要素が増えるほど、低スペックのスマホでカクつきが出やすくなる。
ふたつめは、レイアウトとの結合です。top/left を書き換える実装は、ブラウザにレイアウトの再計算を促しがちで、これも重さの一因になります。さらに、座標を「この要素のこの位置から」と決め打ちで書いていると、後のリニューアルで周囲のマークアップが変わったときに、動きの起点ごとずれます。
みっつめは、保守の属人化です。ライブラリ固有の書き方で軌道を定義していると、そのライブラリを知らない次の担当者が手を入れられず、「触ると壊れるので放置」という塩漬けコードになります。受託では、この「引き継げない動き」がそのまま保守見積もりを押し上げます。
offset-path は、この三つを軽くします。軌道の定義を CSS に持たせ、動き自体は transform 系と同じくブラウザの合成(コンポジット)に乗せられるため、メインスレッドを占有しにくい。JS に頼らない静的な UI 表現は、JSフリーのアンカーポジショニングの記事で扱った「振る舞いを CSS の宣言に寄せる」という方針の延長線上にあります。
offset-path の基本 — 「線路」と「車両」で考える
offset-path の考え方はシンプルで、要素に「線路」を引き、その上を「車両」として走らせるだけです。線路にあたるのが offset-path、車両が線路上のどこにいるかを示すのが offset-distance、そして進行方向に車体を向けるかどうかが offset-rotate です。
たとえば、要素を緩いカーブに沿って右へ動かすなら、こう書きます。
.float-icon {
/* 線路:3次ベジェ曲線で緩いS字を描く */
offset-path: path("M 0 50 C 80 0, 160 100, 240 50");
/* 車両の初期位置:線路の始点 */
offset-distance: 0%;
/* 進行方向に要素を向けない(アイコンを水平に保つ) */
offset-rotate: 0deg;
animation: move-along 6s ease-in-out infinite alternate;
}
@keyframes move-along {
to {
offset-distance: 100%; /* 線路の終点まで走らせる */
}
}
ポイントは、アニメーションさせるのは offset-distance(0%→100%)だけだということです。座標を一つひとつ計算する代わりに、「線路上を 0% から 100% まで進む」という一次元の値だけを動かせばよい。軌道そのものは offset-path に固定されているので、進行のさせ方(速度・イージング・往復)と、軌道の形を、別々に管理できます。
線路の形は path() のベジェ曲線だけでなく、circle() や ellipse() といった基本図形でも指定できます。たとえば要素を円周上で回したいなら次のようになります。
.orbit {
offset-path: circle(120px at center);
offset-rotate: auto; /* 進行方向に要素を向ける(公転する月のように) */
animation: orbit 20s linear infinite;
}
@keyframes orbit {
to { offset-distance: 100%; }
}
offset-rotate: auto にすると、要素が進行方向を向きます。矢印や紙飛行機のアイコンを軌道に沿って飛ばすときに効きますが、ロゴや文字を回したくないときは 0deg で固定する、という使い分けが実務では重要です。
受託で実際に使えるのはどこか
きらびやかなデモは作れますが、受託で投入すべき場所は限られます。私たちが実際に採用したのは、装飾としての常時アニメーションと、スクロールに連動した軽い演出の二つです。
前者は、ヒーロー領域に浮かぶ装飾アイコンやパーティクル状の要素を、ゆっくり循環させる用途。後者は、スクロール量に応じて要素を軌道上で進める用途で、offset-distance を時間ではなくスクロール進捗に紐づけます。スクロール連動については、スクロール駆動アニメーションの記事で扱った animation-timeline: scroll() と組み合わせると、offset-path の軌道をスクロールで進めることが JS なしで書けます。線路を offset-path で、進む速度をスクロールタイムラインで、と役割が分かれるので、両者は相性が良い。
逆に、ユーザー操作で軌道が動的に変わるもの(ドラッグで自由に動かす、データに応じて軌道計算する等)には向きません。そこは素直に JavaScript の領域です。offset-path は「あらかじめ決まった軌道を、軽く走らせる」ことに特化した道具だと割り切るのが、保守を破綻させないコツです。
| 用途 | offset-path | JavaScript |
|---|---|---|
| 装飾の常時ループ・スクロール連動演出 | 向く(軽い・壊れにくい) | 過剰 |
| 進行方向に要素を向ける軌道移動 | 向く(offset-rotate: auto) | 冗長 |
| 操作で軌道自体が動的に変わる | 不向き | 向く |
受託で組み込むときの落とし穴
弊社が制作を引き継いだある美容クリニックのコーポレートサイト(社名は伏せます)では、トップの装飾アニメーションが重いという相談から入りました。前の制作会社の実装を開けると、十数個の装飾要素それぞれに対し、JavaScript が毎フレーム座標を書き換える作りになっていて、スマホでスクロールするとヒーロー全体がもたつく状態でした。
私たちはこの装飾を、要素ごとに offset-path で軌道を定義し、offset-distance を CSS アニメーションで往復させる形に置き換えました。JavaScript は外し、軌道の形と速度をそれぞれ CSS 変数に出して、後から微調整できるようにしました。見た目はほぼ変えていません。やったのは、毎フレーム JS が計算していた動きを、ブラウザが得意な宣言的な動きに寄せ替えただけです。結果、低スペック端末でのカクつきが解消し、JavaScript のバンドルからアニメーション用ライブラリを一つ丸ごと外せました。
この案件で一番効いた学びは、動きを「いつ・どこで」止められるようにしておくことでした。装飾アニメーションは、ユーザーが「視差効果を減らす」設定をしている場合に動かし続けるとアクセシビリティ上の問題になります。offset-path を使う場合でも、次のように prefers-reduced-motion で必ず止める分岐を入れます。
@media (prefers-reduced-motion: reduce) {
.float-icon, .orbit {
animation: none; /* 動きを止め、初期位置に固定 */
}
}
もう一つの落とし穴は、軌道の座標系です。path() の座標は要素の基準位置からのオフセットで解釈されるため、レスポンシブで要素サイズが変わると軌道の見え方も変わります。固定ピクセルの軌道を大画面・小画面の両方でそのまま使うと、スマホで装飾が画面外へはみ出すことがある。ブレークポイントごとに軌道を切り替えるか、circle() のように相対指定しやすい図形を選ぶ、という判断が要ります。なお、こうした実務的な CSS の新機能をどこまで本番投入してよいかの線引きは、モダンCSSネイティブ機能の記事で扱った「Baseline を見て採用可否を決める」考え方がそのまま使えます。
どこから着手するか
「もっと動きを」という要望に、反射的にライブラリを足すのをやめるところから始めると、サイトは軽くなります。あらかじめ軌道が決まっている装飾やスクロール演出なら、まず offset-path で書けないかを検討する。書ければ JavaScript を一つ減らせて、動きの定義が CSS に残るので次の担当者も追えます。
最初の一歩としては、いま動いている装飾アニメーションのうち「軌道が固定されているもの」を一つ選び、offset-path + offset-distance に置き換えてみることをお勧めします。そのうえで prefers-reduced-motion の分岐と、レスポンシブでの軌道のはみ出しだけ確認すれば、本番に出せる品質になります。
サイトの動きが重い、リニューアルのたびにアニメーションが壊れる、ライブラリ依存を減らしたい——そうしたお悩みがあれば、グリームハブのお問い合わせからご相談ください。現行サイトのアニメーション実装を拝見し、CSS ネイティブに寄せられる部分とそうでない部分を切り分けたうえで、軽く保守しやすい形に作り直します。