CSSとJavaScriptでスクロールアニメーションを実装する方法【レスポンシブ対応】

CSSとJavaScriptでスクロールアニメーションを実装する方法【レスポンシブ対応】

2020年7月14日

ページをスクロールするとコンテンツや画像がアニメーションで表示されるサイトってカッコいいですよね!
今回はCSSとJavaScriptで簡単なスクロールアニメーションを実装する方法を解説します。

スクロールアニメーションの実装イメージ

スクロールアニメーションの考え方

スクロールアニメーションを実装する方法は色々ありますが、今回は出来るだけシンプルな方法で実装しようと思います。具体的には以下の仕様で実装します。

  1. アニメーションさせたい要素に.animationというクラスを付ける
  2. JavaScriptでスクロールを監視し、.animationの要素がトリガーに接したら.showというクラスを付ける
  3. CSSで.showをアニメーションさせる

JavaScriptはスクロールのトリガーに使うだけで、アニメーションはCSSで実装する形になります。

ディレクトリ構成

以下のディレクトリ構成を想定して解説していきます。

.
├ css/
│ └ style.css
├ img/
│ ├ img1.jpg
│ ├ img2.jpg
│ ├ img3.jpg
│ ├ img4.jpg
│ └ img5.jpg
├ js/
│ └ script.js
└ index.html

index.htmlのコード

3つのセクションに分けてアニメーションを実装します。

1つ目のセクションはフェードインで画像を表示します。
2つ目のセクションは3つの画像を時間差で表示します。
3つ目のセクションは白と黒の要素がスライドした後に画像を表示します。

index.htmlの内容は以下のようになります。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>スクロールアニメーション</title>
  <link rel="stylesheet" href="css/style.css">
</head>
<body>
  <div class="info">
    <p>スクロールしてください</p>
  </div>

  <p>フェードインで画像が表示</p>
  <div class="fadein animation">
    <img src="img/img1.jpg" alt="画像1">
  </div>

  <p>画像が順番に表示</p>
  <div class="order animation">
    <img src="img/img2.jpg" alt="画像2">
    <img src="img/img3.jpg" alt="画像3">
    <img src="img/img4.jpg" alt="画像4">
  </div>

  <p>デザイン要素がスライドして画像が表示</p>
  <div class="slide animation">
    <img src="img/img5.jpg" alt="画像5">
  </div>

  <!-- アニメーション開始位置の目印 -->
  <div class="trigger"></div>

  <script src="js/script.js"></script>
</body>
</html>

.fadeinが1つ目のセクション、.orderが2つ目のセクション、.slideが3つ目のセクションです。
.triggerはアニメーションの開始位置の目印で、.trigger.animationと交差したらアニメーションがスタートします。

style.cssのコード

CSSでスタイルを整えます。
style.cssの内容は以下のようになります。

/* インフォメーション */
.info {
  height: 1000px;
}

/* フェードインで画像を表示 */
.fadein {
  opacity: 0;
  transition: all 1s;
  margin-bottom: 200px;
}
.fadein img {
  width: 100%;
  height: auto;
}
.fadein.show {
  opacity: 1;
}

/* 順番に画像を表示 */
.order {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-bottom: 200px;
}
.order img {
  max-width: 100%;
  height: auto;
  opacity: 0;
  transform: translateY(100px);
}
.order img:nth-child(1) {
  transition: all 1s;
}
.order img:nth-child(2) {
  transition: all 1s 0.5s;
}
.order img:nth-child(3) {
  transition: all 1s 1s;
}
.order.show img {
  opacity: 1;
  transform: translateY(0);
}

@media (min-width: 768px) {
  .order {
    flex-direction: row;
  }
  .order img {
    width: 33.33%;
  }
}

/* 白黒の要素がスライドした後に画像を表示 */
.slide {
  position: relative;
  overflow: hidden;
  opacity: 0;
  margin-bottom: 200px;
}
.slide::before,
.slide::after {
  content: '';
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
.slide::before {
  z-index: 10;
  background-color: #fff;
  transition: all 0.5s 0.5s;
}
.slide::after {
  z-index: 20;
  background-color: #000;
  transition: all 0.5s;
}
.slide img {
  width: 100%;
  height: auto;
}
.slide.show {
  opacity: 1;
}
.slide.show::before {
  transform: translateX(100%);
}
.slide.show::after {
  transform: translateX(100%);
}

/* アニメーション開始位置の目印 */
.trigger {
  position: fixed;
  top: 50%;
  right: 0;
  width: 100px;
  height: 0;
  border-bottom: 1px solid #000;
}

まずは.fadein.order.slideのアニメーション前のスタイルを指定し、それぞれのクラスに.showを追加してアニメーション後のスタイルをしていしています。
アニメーションの時間や遅延はtransitionプロパティで指定しています。

script.jsのコード

スクロールすると.animationに対して.showを追加するJavaScriptを書きます。
script.jsの内容は以下のようになります。

const animation = document.querySelectorAll('.animation');
const options = {
  root: null,
  rootMargin: "-50% 0px",
  threshold: 0
};
animation.forEach((target) => this.onIntersect(target, options));

function onIntersect(target, options = {}) {
  const observer = new IntersectionObserver(this.addShowClass, options)
  observer.observe(target)
};

function addShowClass(entries) {
  for (const e of entries) {
    if (e.isIntersecting) {
      e.target.classList.add("show")
    }
  }
};

IntersectionObserverを使って要素の交差を監視していますが詳しい解説は省きます。
IntersectionObserverについては以下の記事が大変参考になりました。

ウェブのリッチな表現としてスクロールに応じたエフェクトがあります。これまでJavaScriptのscrollイベントで実装していましたが、Intersectio…
ics.media

rootMarginでアニメーションの開始位置を指定しています。
rootMargin: "-50% 0px"と指定すると、.animationがビューポートの縦中央に接したらアニメーションが始まります。
もっと早くアニメーションを開始したい場合は、rootMargin: "-20% 0px"のように指定します。

まとめ CSSとJavaScriptでスクロールアニメーションを実装する

今回はtransitionプロパティでアニメーションを指定しましたが、animationプロパティと@keyframesでアニメーションを指定してもOKです。
animationプロパティでのアニメーションについては以下の記事で解説しています。

CSSだけでホームページのアニメーションを実装する方法
ホームページを開いた時に、画像やテキストがアニメーションするとかっこいいですよね。以前はJavaScriptでアニメーションを実装することが多かったですが、CS…
ryob.net


CSSだけでは実現できない複雑なアニメーションを作りたい場合は、GSAP(TweenMax)というJSライブラリを使うのがオススメです。
いろいろなアニメーションを実装できるので興味がある方は調べてみてください。

以上が、CSSとJavaScriptでスクロールアニメーションを実装する方法でした。