animation-range
タイムラインのどの区間でアニメを進めるかを決めるプロパティ。 scroll-driven の表現力はここで決まる。
構文
animation-range: <start> <end>;
animation-range-start: <start>;
animation-range-end: <end>;
値の種類
| 値 | 意味 |
|---|---|
| normal | タイムライン全体(既定) |
| length / percentage | 絶対値(scroll()) |
| cover <%> | cover の何 % |
| contain <%> | contain の何 % |
| entry <%> | entry の何 % |
| exit <%> | exit の何 % |
| entry-crossing | 境界を越える瞬間 |
| exit-crossing | 境界を越え終わる瞬間 |
cover / contain / entry / exit の関係
要素のライフサイクル
時間 →
[要素は画面外(下)]
↓
┌─ entry 始まる ─┐
│ │
│ ← cover 開始 │
│ │
[要素の上端が画面下端に来た] │
↓ │
│ │
│ ← ここまで entry 進行 │
│ │
[要素全体が画面内に入った]
└─ entry 終わり = contain 開始 ─┘
↓
[完全表示中]
↓
┌─ contain 終わり = exit 開始 ─┐
│ │
[要素の下端が画面上端に来た] │
│ │
│ ← exit 進行 │
│ │
│ ← ここで cover 終わり │
│ │
└─ exit 終わり ─┘
↓
[要素は画面外(上)]
例で理解する
「現れたら 1 回フェードイン」
animation-range: entry 0% entry 100%;
「現れてから完全表示の真ん中まで」
animation-range: entry 0% cover 30%;
「完全表示中だけ動く」
animation-range: contain 0% contain 100%;
「消えていく時だけ」
animation-range: exit 0% exit 100%;
「現れてから消えるまで全部」
animation-range: cover 0% cover 100%;
scroll() で使う場合
/* % */
animation-range: 0% 100%; /* 全スクロール */
animation-range: 30% 70%; /* 中央 40% */
/* 絶対 px */
animation-range: 200px 800px;
/* vh */
animation-range: 0vh 80vh;
個別指定
animation-range-start: entry 0%;
animation-range-end: cover 30%;
複数 animation の範囲を別々に
.parallax-card {
animation:
fade-in linear both,
drift linear both;
animation-timeline: view(), view();
animation-range:
entry 0% entry 100%, /* fade-in は入る間 */
cover 0% cover 100%; /* drift は cover 全体 */
}
境界周辺の挙動
- entry 0% = 要素が画面下から「ちょうど現れた瞬間」
- entry 100% = 要素が完全に画面内に入った瞬間
- exit 0% = 要素が完全表示から外れ始める瞬間
- exit 100% = 要素が完全に消えた瞬間
animation-delay / animation-duration
scroll-driven ではdelay と duration もスクロール量で解釈される(時間ではなく)。
- auto 推奨(タイムラインの長さに合わせる)
- 明示的にずらしたいなら animation-range で調整
fill-mode と組合せ
.elem {
animation: reveal linear both;
animation-range: entry 0% entry 100%;
/* ↑
* 範囲外(画面外 / 完全表示後)でも
* fill-mode: both で値を保持
*/
}
chained range(複数段階)
現状、1 つの animation に対して 1 つの range のみ。多段階は複数の animationを組合せる:
.story {
animation:
appear linear both,
move linear both,
fade linear both;
animation-timeline: view(), view(), view();
animation-range:
entry 0% entry 100%,
contain 0% contain 100%,
exit 0% exit 100%;
}
@keyframes appear { from { opacity: 0; } to { opacity: 1; } }
@keyframes move { from { transform: translateY(0); } to { transform: translateY(-30px); } }
@keyframes fade { from { opacity: 1; } to { opacity: 0; } }
視覚化のための DevTools
- Chrome DevTools のAnimationsパネルで進行を可視化
- scroll-timeline はTimeline タブで確認できる
- 進行度 0〜1 がスライドバーで動かせる
キーフレームの中の % との対応
@keyframes story {
0% { opacity: 0; transform: translateY(40px); }
50% { opacity: 1; transform: translateY(0); }
100% { opacity: 0; transform: translateY(-40px); }
}
.elem {
animation: story linear both;
animation-timeline: view();
animation-range: cover 0% cover 100%;
}
@keyframes の 0% / 50% / 100% がanimation-range の 0% / 50% / 100% に対応する。
パーセントは「区間の中の %」
entry 50% はentry の半分まで進んだ時点。
全体の 50% ではない。
失敗パターン
| 症状 | 対処 |
|---|---|
| カードが画面下から半分くらいで終わる | entry 0% cover 30% → entry 0% entry 100% に拡張 |
| 狭すぎてアニメが見えない | animation-range をもっと広く |
| 初期値に戻ってちらつく | fill-mode: both / forwards |
| contain が短くて使えない | 要素が小さい / 画面が大きい場合は contain は短い |
よく使う組合せ
entry 0% cover 30% がリビールの黄金比。 現れ始めから完全表示まで(+α)の体感が良い。