定義
スクロールを下げていく途中で要素が画面内に入ってくる瞬間にすっと現れる(fade/slide)ようにしつつ、それを JavaScript なしで CSS だけで作りたいときに使う技法である。
肝は二つの CSS プロパティだ。animation-timeline: view() は「このアニメーションの進行を、時間ではなくこの要素が画面(viewport — ユーザーに実際に見えるブラウザ表示領域)にどれだけ入ってきたかに合わせよ」という意味だ。animation-range: entry 0% entry 60% は「要素が画面に入り始めた地点(entry 0%)から、60% ほど入った地点までアニメーションを進行させよ」という意味だ。この二つで、要素がビューポートに入ってくる区間に合わせて opacity(透明度)・transform(位置・大きさの変形)のキーフレーム(keyframes — アニメーションの開始/中間/終了の状態を定義したもの)をマッピングする。
なぜ必要か
問題状況: 同じ「スクロールすると現れる」効果を昔の方式で作ると、IntersectionObserver(要素が画面に入ったかを検知する JS API)で検知し classList でクラスを付けるコードを書かねばならない。すると、サーバーレンダリング後に JS を付ける hydration(サーバーが作った HTML に React のようなフレームワークがイベントを付けて実際に動作させる過程)のタイミング、エフェクトの後始末、そしてアニメーションを切るべきユーザー配慮(reduced-motion)のコードまで、すべて手で管理しなければならない。
CSS view-timeline を使うと、このロジックが宣言的な CSS 数行に縮む。@supports(ブラウザが特定の CSS を対応しているか検査する条件ブロック)の後ろに置けば、対応しないブラウザではアニメーションなしでそのまま即時表示され(内容が消えない)、対応するブラウザだけで控えめな登場効果が付く。
動作原理
- 現す要素にタイムラインと範囲を指定する。
@supports (animation-timeline: view())で包み、未対応ブラウザはこの規則を無視して要素をそのまま見せておく。- アニメーションを望まないユーザーのために
@media (prefers-reduced-motion: reduce)(OS で「動きを減らす」をオンにしたユーザーを検知するメディアクエリ)の中でanimation: noneで切る。 - ページ全体の進行バーのようなものは、要素の進入ではなく文書スクロール全体を基準にする
scroll()タイムラインを使う —view()(要素単位)と役割を分ける。
実務での適用
- リスト項目(
<li>)、統計パネルのような個別のコンテンツブロックにだけ付ける。ページ全体のコンテナに掛けると進入判定が曖昧になる。 - 継続的に繰り返すデモ用のループアニメーションとはクラスを分ける。一つの要素に「スクロール基準」と「時間基準」のタイムラインを混ぜると衝突する。
- 動かすプロパティは
transformとopacityだけを使う。width・topのようなレイアウトプロパティをアニメーションすると、毎フレームレイアウトを再計算する layout thrash(レイアウトの強制再計算が繰り返されて性能が落ちる現象)が起きる。
トレードオフ
- Safari・Chromium の対応範囲は広がる傾向だが、すべてのブラウザ共通ではない — そのため
@supportsで包むのが事実上必須だ。 - 進行区間(range)を長く取りすぎると、スクロールがほぼ終わるまでアニメーションが続いて不自然だ — そのため通常は進入 60% あたりで終わるよう(entry 60%)上限を置く。
使ってはいけない場合
- 検索に重要な最初の画面(above-fold)テキストをまるごと隠す用途。開始の透明度を 0.15 程度に下げるのは構わないが、
display: noneのように完全に隠すと、コンテンツが無いものとして扱われる危険がある。
よくある間違い
- 位置を固定する親(sticky)に
overflow: hiddenを掛け、固定動作と登場効果が同時に壊れる。 - 繰り返しループのキーフレームを付けたクラスと登場(view-reveal)クラスを同じ要素に一緒に掛け、二つのアニメーションが互いを上書きする。
関連概念
- scroll-driven-narrative-layout — スクロール進行に合わせて画面を叙述的に展開する上位のレイアウトパターン
- cls-skeleton-layout-reservation — 登場前に場所を先に確保し、レイアウトがずれ(CLS)ないようにする技法