@scroll-timelineを使ってCSSのみでスクロールアニメーションを実現する
UI開発者 板垣本記事では、現在CSS Working GroupでEditor's Draftとして公開されているScroll-linked animationの仕様書を基に、@scroll-timeline
の機能および使い方について解説します。
そもそもScroll-linked animationとは
Scroll-linked animation※1とはスクロールのオフセット値に関連付けたアニメーションを作成する機能の総称です。
CSSおよびJavaScript(Web Animations API拡張)で利用可能であり、これを活用することで、スクロールをしたらフワッと要素が浮き出る効果や、画面に視差効果を持たすことが今より簡単に実現できるようになります。
次の節からは、CSSで本機能を利用するために必要な「@scroll-timeline
」について言及します※2。
@scroll-timelineとは
@scroll-timeline { <declaration-list> }
「at-rule」の1つで、スクロールアニメーションに必要な操作対象やアニメーションにかかる時間などを定義するためのルールです。
このルールは「timeline-name」という識別子と、「decoration-list」という記述子リストを受け取ります。
timeline-nameには@keyframes
のように任意の文字列を識別子として指定することができ、これをanimation-timelineプロパティ※3に指定した値と同じにすることで、それらを対応付けさせることができます。decoration-listに指定できる記述子にはスクロールアニメーションに必要な情報を記述します。これについては次の項以降で説明いたします。
以下は@scroll-timeline
およびそれに関連する機能の記述例です。
.test {
animation-name: test-animation;
animation-timeline: test-timeline;
animation-duration: 1s;
animation-fill-mode: both;
}
@keyframes test-animation {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@scroll-timeline test-timeline {
start: 0%;
end: 100%;
time-range: 1s;
}
decoration-listに指定できる記述子
本項ではdecoration-listに指定できる記述子を紹介いたします。
source
source記述子にはスクロールアニメーションを実行するための、スクロール可能な要素を指定します。
利用できる値はauto
、none
、selector関数のいずれかで、初期値はauto
です。
値にauto
が指定されている場合は、html要素がセットされるため、任意の要素を指定したい場合はselector
関数を使います。selector関数はid-selector
引数として取ります(id-selector
以外では機能しないので注意してください)。
orientation
orientation記述子にはスクロールタイムラインを進めるためのスクロール方向を指定します。
auto
、block
、inline
、horizontal
、vertical
の4つの値が利用可能で、初期値はauto
です。
初期値のauto
については、これを指定した際に実際の値が何になるのかを仕様から読み取ることができませんでしたが、ScrollTimelineのインターフェースを確認すると初期値にblock
が指定されているので、おそらくCSS側でもautoを指定した際にはblock
として動作するものと考えています。
ちなみにblock
、inline
というのは論理プロパティでの方向を指しています。
start
start記述子にはスクロールタイムラインの開始位置を指定します。値には<scroll-timeline-offset>
が利用できます。
<scroll-timeline-offset>
とは、以下の内容を指しています。
<scroll-timeline-offset> = auto | <length-percentage> | <element-offset>
<element-offset> = selector( <id-selector> ) [<element-offset-edge> || <number>]?
<element-offset-edge> = start | end
つまり、start記述子に指定できるのはauto
、(数値)%
、start
、end
、selector関数、数値の6つのタイプになります。
各タイプが何を表すかは以下の通りです。
- auto: sourceで指定した要素の先端(orientationによって変動)を設定します。
- (数値)%: 指定した数値を基に開始位置を設定します。
- selector関数: 引数で指定した要素を開始位置に設定します。すべての要素が対象というわけではなく、
scroll-timeline
を指定した要素の子孫要素のみが対象となります。 - start: sourceで指定した要素の先端(orientationによって変動)を設定します。
- end: sourceで指定した要素の終端(orientationによって変動)を設定します。
- 数値: 0から1の間で開始位置を設定します。
end
end記述子にはスクロールタイムラインの終了位置を指定できます。値にはstart記述子と同じく<scroll-timeline-offset>
を指定できます。
time-range
time-range記述子には時間(sもしくはms)を指定することで、スクロールによって表示されるアニメーションの進行度合いを設定できます。
いささかややこしいのですが、例えば以下のコードではtime-range
に5s
と指定してあり、animation-duration
には10s
と指定されています。
この場合、スクロールによって表示されるアニメーションの範囲は@keyframes
で言うところの50%
までになります。
html {
height: 200vh;
}
.box {
width: 50px;
height: 50px;
background-color: gold;
position: fixed;
top: calc(50% - 25px);
animation-name: box-animation;
animation-timeline: box-animation-timeline;
animation-duration: 10s;
animation-fill-mode: both;
}
@keyframes box-animation {
0% {
left: 0%;
}
50% {
left: 50%;
}
100% {
left: 100%;
}
}
@scroll-timeline box-animation-timeline {
start: 0%;
end: 100%;
time-range: 5s;
}
以下のgif画像は上記のコードを実行したときの表示です。
スクロールバーが一番上にあるときは矩形がleft: 0%
の位置にあり、一番下までいくと100%
のleft: 100%
の位置ではなく50%
のleft: 50%
の位置に移動していることがわかると思います。
スクロールバーが一番下にあるとき、left: 100%
の位置に移動させたいのであれば、time-range
をanimation-duration
と同じ値にします(今回の場合だと10s
)。
この記述子の初期値はauto
です。仕様を見る限り、end記述子の値を継承するものと考えているのですが、auto
を指定すると動作しなくなってしまいます。
デモ
本デモでは、画面をスクロールすることで、画面中央に表示されているロゴが画面左上に移動するアニメーションと、テキストがフワッと表示されるアニメーションを実行しています。
また、ページ下部にあるボックスをスクロールすることで、それをトリガーとして、それの下にあるテキストがフワッと表示されるようになっています。この機能にはあまり実用性がありませんが、アニメーションのトリガー変更の例として見ていただければと思います。
閲覧されているブラウザが本機能に対応している場合はこちらのCodePenから実際の挙動をご確認いただけます。
おわりに
認知率、使用率ともに上昇中のCSS変数をはじめとする、プログラミング言語ライクな機能がだいぶCSSに追加および検討されてきている気がしています。
便利になっていく一方で、元来「装飾」を担当していたCSSと、「動的な処理」を担当していたJavaScriptの機能分担がわかりにくくなるのではと危惧しております。
どのような機能でも「なんとなく便利だから使う」のではなく、その機能が持つ特徴やどのような問題を解決するために作られたのかを理解して、「必要だから使う」ことを意識してこれらの機能を使用できるとよいのかもしれません。
※1 現時点では実験的機能であり、Chrome Canaryで「enable-experimental-web-platform-features」フラグを有効にしなければ機能しません。
※2 本記事に書かれている内容から仕様が変更される可能性もあるため、使用する際は十分な鮮度確認をお願いいたします。
※3 animation-timeline
とは、アニメーションとタイムラインルールを関連付けさせるためのプロパティです。このプロパティが存在しない場合は、代わりにanimation-name
の値を見てアニメーションとタイムラインルールの対応付けを行います(現状だと実装には至っていないようです)。