下記のプロパティが追加されました。
方法は簡単で、通常のアニメーションの時間の代わりに animation-timeline: scroll()
を指定するだけです。
@keyframes my-frame { 0% { scale: 100% 100%; } 50% { scale: 10% 100%; } 100% { scale: 100% 100%; } } .my-example-scroll { width: 300px; height: 200px; border: 1px solid #ccc; overflow: auto; padding: 40px 8px; .inner-box { height: 1000px; background-color: red; animation: my-frame ease-in; animation-timeline: scroll(); } }
<div class="my-example-scroll"> <div class="inner-box"></div> </div>
scroll()
には下記の引数を指定することができます。
scroll(<scroller> <axis>)
<scroller>
はアニメーションがどの要素のスクロールに追従するかを指定します。
<axis>
はアニメーションがどの方向のスクロールに追従するかを指定します。
scroll()
はスクロールバーのスクロール開始を 0%、スクロール終了を 100% としますが、view()
を指定すると、アニメーション対象のコンテンツが画面の表示されている部分(スクロールポート)に入ってくるタイミングを 0%、出ていくタイミングを 100% としたアニメーションにすることができます。
.my-example-view { width: 300px; height: 200px; border: 1px solid #ccc; overflow: auto; .inner-box { height: 10px; margin: 300px auto; background-color: red; animation: my-frame ease-in; animation-timeline: view(); } }
<div class="my-example-view"> <div class="inner-box"></div> </div>
アニメーション対象コンテンツがスクロールポートに入り始めた時は横幅 100% ですが、中間地点(50%)では 10% の長さになり、出る時に 100% の長さに戻ります。
view()
には下記の引数を指定できます。
view(<axis> <view-timeline-inset>)
<axis>
はアニメーションがどの方向のスクロールに追従するかを指定します。
<view-timeline-inset>
はアニメーションのインセット情報(終了位置と開始位置)を長さまたはパーセントで指定します。view(30% 20%)
は入り始めて 20% の箇所でアニメーションが始まり、終わりから 30% の箇所でアニメーションが終わります。終了・開始の順で指定するので注意してください。値をひとつのみ記述した場合は開始・終了同じ値と見なされます。値には負数を指定することもできます。
下記の例では、アニメーション対象要素がスクロールポートに入ってから 20% 経過したところでアニメーションが始まり、出ていく 30% 前のところでアニメーションが終了します。
animation-timeline: view(30% 20%);
スクロールバーを持つ要素とアニメーション対象要素の関係は、スクロールバーを持つ要素で scroll-timeline-name
, scroll-timeline-axis
を用いてタイムライン名とスクロール方向を定義し、アニメーション対象要素から animation-timeline
で名前参照することもできます。
ただし名前参照が可能なのは祖先要素のみです。祖先要素以外で参照したい時は後述の timeline-scopt
を使用します。
.my-example-scroll-name { width: 300px; height: 200px; border: 1px solid #ccc; overflow: auto; padding: 40px 8px; scroll-timeline-name: --my-scroll-name; /* タイムライン名を定義 */ scroll-timeline-axis: block; .inner-box { height: 1000px; background-color: red; animation: my-frame ease-in; animation-timeline: --my-scroll-name; /* タイムライン名を参照 */ } }
<div class="my-example-scroll-name"> <div class="inner-box"></div> </div>
scroll-timeline
は scroll-timeline-name
と scroll-timeline-axis
のショートハンド(一括指定プロパティ)です。
.my-example-scroll-name { ... /* scroll-timeline-name: --my-scroll-name; */ /* scroll-timeline-axis: block; */ scroll-timeline: --my-scroll-name block; ... }
ビュー駆動タイムラインも同様、スクロールポートの出入りを判断する要素で view-timeline-name
, view-timeline-axis
, view-timeline-inset を用いてタイムライン名、スクロール方向、インセット情報を定義し、アニメーション対象要素から animation-timeline
で名前参照することができます。
こちらも、view-timeline-name
を指定する要素は、名前を参照する要素の祖先である必要があります。
.my-example-view-name { width: 300px; height: 200px; border: 1px solid #ccc; overflow: auto; .inner-box { margin: 300px auto; padding: 20px; background-color: red; view-timeline-name: --my-view-name; view-timeline-axis: block; view-timeline-inset: 30% 20%; .animation-box { height: 10px; background-color: blue; animation: my-frame ease-in; animation-timeline: --my-view-name; } } }
<div class="my-example-view-name"> <div class="inner-box"></div> <div class="animation-box"></div> </div>
サンプルでは、赤い領域がスクロールポートに入った時を 0%、出る時を 100% として、青い領域がアニメーションします。
view-timeline
は view-timeline-name
と view-timeline-axis
と view-timeline-inset
のショートハンド(一括指定プロパティ)です。
.my-example-view-name { .inner-box { ... /* view-timeline-name: --my-view-name; */ /* view-timeline-axis: block; */ /* view-timeline-inset: 30% 20%; */ view-timeline: --my-view-name block 30% 20%; } }
ある要素 A で scroll-timeline-name や view-timeline-name を用いて定義したタイムライン名は A の子孫要素からしか参照できませんが、A の祖先要素 X で timeline-scope を宣言するとスコープが拡大され、X の子孫要素すべてがタイムライン名を参照できるようになります。
X { timeline-scope: --my-name; /* タイムライン名スコープを拡大する */ A { scroll-timeline-name: --my-name; /* タイムライン名を定義する */ } B { animation-timeline: --my-name; /* タイムライン名を参照できるようになる */ } }
.my-example-scope-A { display: flex; gap: 8px; timeline-scope: --my-scope-name; .my-example-scope-X { height: 200px; width: 200px; border: 1px solid #ccc; overflow: auto; scroll-timeline-name: --my-scope-name; .inner-box { height: 1000px; x-background-image: linear-gradient(to bottom, red, blue); } } .my-example-scope-Y { .inner-box { height: 30px; width: 200px; background-color: red; animation: my-frame ease; animation-timeline: --my-scope-name; } } }
<div class="my-example-scope-A"> <div class="my-example-scope-X"> <div class="inner-box"></div> </div> <div class="my-example-scope-Y"> <div class="inner-box"></div> </div> </div>
animation-range
は、アニメーション対象要素に設定するプロパティで、表示領域(スクロールポート)におけるアニメーションの開始・終了タイミングを指定します。
animation: my-frame linear; animation-timeline: view(); animation-range: entry;
タイミングには下記のいずれかを指定します。
cover
と同じ動作のようです。
cover
, contain
, entry
, exit
の違いについては下記のデモで確認してください。
entry-crossing
は entry
と、exit-crossing
は exit
と似ていますが、アニメーション対象要素の高さがスクロールよりも高いときの動作が異なります。entry
はスクロール対象の上部がスクロールポートの上部に達するとアニメーションが終了するのに対して、entry-crossing
はスクロール対象の下部がスクロールポートの下部(終了側エッジ)を横切り終えるまでアニメーションは終了しません。
レンジ名を二つ記述することで、開始と終了に別のレンジ名を指定することもできます。
animation-range: contain cover;
レンジ名の後に長さやパーセンテージを記述することで、開始や終了のタイミングをずらすことができます。cover
と contain
の場合はスクロールポートの下限を 0%、上限を 100% と見なします。entry
と exit
の場合はスクロール要素の高さの上限を 0%、下限を 100% と見なします。
animation-range: cover 0% contain 70%; /* 入り始めてから70%進むまで */ animation-range: contain 0% exit 50%; /* 入り終わってから50%出るまで */ animation-range: contain 20% contain 80%; /* 入り終わってから20%~80%の間で */ animation-range: entry 70% exit 70%; /* 70%入ってから70%出るまで */