【CSS】スクロールに合わせたアニメーションが作れる「スクロール駆動アニメーション」とは？

## はじめに
みなさんは「**スクロール駆動アニメーション**」を知っていますか？

**スクロール駆動アニメーション**は、Chrome115でリリースされた、CSSだけでスクロールに合わせたアニメーションが作れるようになるプロパティです。

今までは、JavaScriptなどを駆使して、スクロールアニメーションを作っていましたが、
スクロール駆動アニメーションを使うことで、簡単にスクロールアニメーションを作れるようになります。

この記事では、そんな**スクロール駆動アニメーション**の基本的な使い方・プロパティについて解説します。

## スクロール駆動アニメーション

**スクロール駆動アニメーション**は、SSだけでスクロールに合わせたアニメーションが作れるようになるプロパティです。
スクロール駆動アニメーションには、2種類のアニメーションタイムラインが定義されています。

### 01. Scroll Progress Timeline
Scroll Progress Timelineは、スクロールできるコンテナー内のスクロール位置によって、アニメーションを指定できるタイムラインです。

![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/41324529-a4e9-e1a4-452d-c51ff43b7bc4.png)

上記の画像のように、開始スクロール位置を`0%`、終了スクロール位置を`100%`として、アニメーションが動きます。

#### サンプル
このサンプルでは、スクロール位置に合わせて、X軸方向の`scale`を、`0.5` から `1` へアニメーションします。
<p class="codepen" data-height="450" data-default-tab="result" data-slug-hash="JjeQEpw" data-editable="true" data-user="sp_degu" style="height: 450px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/JjeQEpw">
  Scroll Driven Animations - sample 01</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

#### 基本的な使い方
Scroll Progress Timelineの基本的な使い方は、アニメーションさせたい要素の `animation-timeline` に `scroll()` 関数を使い、`animation` に `@keyframes` を指定するだけです。

##### scroll()
```
scroll(<scroller> <axis>)
```
*<font color="gray">ref: [scroll() - MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline/scroll)</font>*

`scroll()` は引数に `<scroller>` と `<axis>` を受け取ることができ、上記のように指定することができます。

+ **scroller**：スクロールする基準を決める値 *<font color="gray">（省略可）</font>*
  + `nearest`：最も近いスクロールする先祖要素を基準にする *<font color="gray">（デフォルト）</font>*
  + `root`：ドキュメントビューポートを基準にする
  + `self`：指定した要素自体を基準にする
+ **axis**：スクロール方向を決める値 *<font color="gray">（省略可）</font>*
  + `block`：ブロック方向のスクロールを基準にする *<font color="gray">（デフォルト）</font>*
  + `inline`：インライン方向のスクロールを基準にする
  + `y`：y軸方向のスクロールを基準にする
  + `x`：x軸方向のスクロールを基準にする

　
具体的に `scroll()` を使うと以下のようなCSSになります。

```sample.css
@keyframes scroll-anim {
  from { scale: 0.5 1; }
  to { scale: 1 1; }
}

.inner {
  animation: scroll-anim linear;
  animation-timeline: scroll();
}
```
*<font color="gray">※ `@keyframes`では、`from / to` だけでなく、パーセント`%`での指定もできます。</font>*
*<font color="gray">※ イージングは、`linear` 以外も使うことが可能です。</font>*


### 02. View Progress Timeline
View Progress Timelineは、スクロールできるコンテナーのスクロールポートを基準としてアニメーションを指定できるタイムラインです。

基準となるアニメーション範囲は、以下の種類があります。

**① cover**
`cover` は、スクロールポートの全範囲がアニメーション範囲になります。
そのため、要素がスクロールポートに1px以上入ってから、要素が完全に出るまでアニメーションします。
![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/c9c5be0a-ca99-b173-7b7d-3901a112dd25.png)

**② entry**
`entry` は、スクロールポートに要素が見える範囲がアニメーション範囲になります。
そのため、要素がスクロールポートに1px以上入ってから、全要素が見えるようになるまでアニメーションします。
![image3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/f1ab4c2b-513e-14ae-b777-53a74066f7d4.png)

**③ exit**
`exit` は、スクロールポートに要素が見えなくなる範囲がアニメーション範囲になります。
そのため、要素がスクロールポートに1px以上出てから、全要素が見えなくなるまでアニメーションします。
![image4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/4cdf326d-0fc3-879d-0fca-71f7804eb69a.png)

**④ entry-crossing**
`entry-crossing` は、スクロールポートの終了境界エッジを横切っている範囲がアニメーション範囲になります。
そのため、スクロールコンテナーの終了境界エッジを要素が重なり始めてから、終わるまでアニメーションします。
![image5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/bd206819-2b00-0053-1fe6-27fd002a7395.png)

**⑤ exit-crossing**
`exit-crossing` は、スクロールポートの開始境界エッジを横切っている範囲がアニメーション範囲になります。
そのため、スクロールコンテナーの開始境界エッジを要素が重なり始めてから、終わるまでアニメーションします。
![image6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/fbccfe95-8021-068a-9d8d-a085cb29214d.png)

**⑥ contain**
`contain` は、要素がスクロールポートに入っている範囲がアニメーション範囲になります。
そのため、全要素がスクロールポート内に入ってから、要素がで始めるまでアニメーションします。
![image7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/093f8dc7-a21a-a092-7de4-335935e8e356.png)

#### サンプル
このサンプルでは、基準となるスクロール範囲に合わせて、`width`をアニメーションします。

+ `cover` → `width`を、`50%` から `100%` へアニメーションします。
+ `entry` → `width`を、`50%` から `100%` へアニメーションします。
+ `exit` → `width`を、`100%` から `50%` へアニメーションします。
+ `entry-crossing` → widthを、`50%` から `100%` へアニメーションします。
+ `exit-crossing` → widthを、`100%` から `50%` へアニメーションします。
+ `contain` → widthを、`100%` から `50%` へアニメーションします。

<p class="codepen" data-height="450" data-default-tab="result" data-slug-hash="abQgJeZ" data-editable="true" data-user="sp_degu" style="height: 450px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/abQgJeZ">
  Scroll Progress Timeline</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

#### 基本的な使い方
View Progress Timelineの基本的な使い方は、アニメーションさせたい要素の `animation-timeline` に `view()` 関数を使い、`animation-range` でアニメーションの範囲を決め、`animation` に `@keyframes` を指定するだけです。

##### view()
```
view(<axis> <view-timeline-inset>)
```
*<font color="gray">ref: [view() - MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline/view)</font>*

`view()` は引数に `<axis>` と `<view-timeline-inset>` を受け取ることができ、上記のように指定することができます。

+ **axis**：スクロール方向を決める値 *<font color="gray">（省略可）</font>*
  + `block`：ブロック方向のスクロールを基準にする *<font color="gray">（デフォルト）</font>*
  + `inline`：インライン方向のスクロールを基準にする
  + `y`：y軸方向のスクロールを基準にする
  + `x`：x軸方向のスクロールを基準にする
+ **view-timeline-inset**：要素のアニメーションを調整するオフセット値 *<font color="gray">（省略可）</font>*
  + `<length-percentage>`：インセット値を1~2つ指定できる *<font color="gray">（デフォルト: auto）</font>*
    + auto, 50px, 25%, 3rem, etc.

##### animation-range
```
animation-range: entry 0% entry 100%;
```
*<font color="gray">ref: [animation-range - MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-range)</font>*

`animation-range` プロパティは、上記のようにスクロールアニメーションがスタートする位置・終了する位置とアニメーション範囲を指定することができます。


細かい指定は、↓こちらのscroll-driven-animationsジェネレーターを触りながら、調整するのがわかりやすいと思います。

https://scroll-driven-animations.style/tools/view-timeline/ranges/#range-start-name=cover&range-start-percentage=0&range-end-name=cover&range-end-percentage=100&view-timeline-axis=block&view-timeline-inset=0&subject-size=smaller&subject-animation=reveal&interactivity=clicktodrag&show-areas=yes&show-fromto=yes&show-labels=yes


具体的に `view()` と `animation-range`を以下のようなCSSになります。

```sample.css
@keyframes scroll-anim {
  from { width: 50%; }
  to { width: 100%; }
}

.inner {
  animation: scroll-anim linear;
  animation-timeline: view();
  animation-range: cover 0% cover 100%;
}
```
*<font color="gray">※ `@keyframes`では、`from / to` だけでなく、パーセント`%`での指定もできます。</font>*
*<font color="gray">※ イージングは、`linear` 以外も使うことが可能です。</font>*

## まとめ
この記事では、Chrome115でリリースされた、CSSだけでスクロールに合わせたアニメーションが作れるようになる**スクロール駆動アニメーション**について解説しました。
スクロール駆動アニメーションは、CSSだけでスクロールに合わせたアニメーションを制御できる素晴らしく、待ちに待ったプロパティです。

具体的なサンプルコードも載せているので、ぜひ試してみてください。

---

最後まで読んでくださってありがとうございます！

普段はデザインやフロントエンドを中心にQiitaに記事を投稿しているので、ぜひQiitaのフォローとX(Twitter)のフォローをお願いします。

https://twitter.com/degudegu2510