スクロール動作に連動してアニメーションするjQurey&CSS実装 (スライドイン・フェードイン)
本記事では、ページをスクロールして画面内に該当のコンテンツが入ったらスライドインして表示をするという動作を、jQueryで実装する方法について解説します。
この実装は初心者には難しく見えるかもしれませんが、仕組みを知ると簡単で、JavaScriptとCSSの組み合わせで簡単に実装が可能です。
この記事を書いている僕は、フロントエンドのプログラマー(フリーランス)として、これまで3年以上のWeb制作経験があり、HTMLやCSSのマークアップからJavaScriptのフレームワークであるVue,React,Nuxtなどフロントエンドの開発を得意としています。
この記事を読むことによって、スクロール動作に連動してアニメーションする方法がわかるようになります。
単純にコードをコピペではなく、動作の仕組みが理解できれば似たような動作について応用ができます。
GitHubのサンプルコード
サンプルコードとして、GitHubにコードを上げています。
https://github.com/it-web-life/jquery_scroll_action_animation
※「git clone」するか、緑色の「Code」ボタンをクリックして「Download ZIP」をクリックしてダウンロードして中身を解凍してください。
ディレクトリ構成
- 「base」ディレクトリ以下:スクロール動作に連動してアニメーションする処理を実装する前のベースとなるコード
- 「complete」ディレクトリ以下:スクロール動作に連動してアニメーションする処理を実装したコード
実装前の動作は以下の通りです。(アニメーションなし)
https://it-web-life.github.io/jquery_scroll_action_animation/base/index.html
スクロールでアニメーションされる原理
どのようにアニメーションさせるかを解説します。
動作としては、以下を想定しています。
- 縦長に長いページにて、画面内に入っていないコンテンツがある。
- スクロールすることによって、見えていないコンテンツが画面内に入ってきたら、フェードインのアニメーションで表示される。
これを実現する手段としては、以下の通りです。
- ①スクロールして画面内にフェードインする要素が入ってきたら、その要素に「.is-show」Classを付与する。
- ②フェードインする要素は「.is-show」が付いていない元の状態では、CSSが「opacity: 0」と「translateX(50%)」などの設定によりずれた位置に非表示になっている。
「.is-show」が付いた状態では、CSSが「opacity:1」と「translateX(0)」で本来表示される位置に表示されるようにする。 - ③フェードインする要素には、transitionをつけて、「.is-show」がつくとアニメーションするように設定する。
スクロールでアニメーションする実装
スクロール、アニメーションに関する実装を順番に解説していきます。
HTML部分
▼index.html (script読み込み)
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-throttle-debounce/1.1/jquery.ba-throttle-debounce.js"></script>
<script src="script/script.js"></script>
今回はスクロール処理を使うので、throttleも使うためjQueryのthrottleプラグインも読み込ませます。
また、以下の3箇所のアニメーションを付ける要素に、「.js-fade-animation」Classをつけておき、画面内に入ったら、「.is-show」Classが付与されるようにしておきます。jQueryの処理で、「.js-fade-animation」が付いている箇所に「.is-show」をつけるよう後ほど処理を追加します。
▼index.html (.js-fade-aniimation Class付与)
<section class="dummy dummy--wide">
<h2 id="second" class="title">2番目の猫 右からフェードイン</h2>
<div class="content">
<p class="content__text">ダミーテキストです。〜ダミーテキストです。</p>
<div class="js-fade-animation content__image">
<img class="imageCat" src="./images/cat_02.jpg" alt="cat">
</div>
</div>
</section>
<section class="dummy dummy--wide">
<h2 id="third" class="title">3番目の猫 右から連続フェードイン</h2>
<p class="text">ダミーテキストです。〜ダミーテキストです。</p>
<ul class="js-fade-animation list">
<li class="item"><img class="imageCat" src="./images/cat_03.jpg" alt="cat"></li>
<li class="item"><img class="imageCat" src="./images/cat_04.jpg" alt="cat"></li>
<li class="item"><img class="imageCat" src="./images/cat_05.jpg" alt="cat"></li>
</ul>
</section>
<section class="dummy dummy--wide">
<h2 id="third" class="title">4番目の猫 下から連続フェードイン</h2>
<p class="text">ダミーテキストです。〜ダミーテキストです。</p>
<ul class="js-fade-animation fadelist">
<li class="fadeitem"><img class="imageCat" src="./images/cat_06.jpg" alt="cat"></li>
<li class="fadeitem"><img class="imageCat" src="./images/cat_07.jpg" alt="cat"></li>
<li class="fadeitem"><img class="imageCat" src="./images/cat_08.jpg" alt="cat"></li>
</ul>
</section>
CSS部分
CSSは、3種類フェードインのアニメーションを作るので、3つに分けて説明します。
1. 「2番目の猫」 右からフェードイン
右からフェードインするアクションを入れます。
「transform」「opacity」「transition」を追加します。
▼css/style.css
.content__image {
width: 50%;
margin: 10px;
transform: translateX(50%);
opacity: 0;
transition: all 0.75s ease-in-out 0.5s;
}
.content__image.is-show {
transform: translateX(0);
opacity: 1;
}
「.content__image」では初期値で以下のようになるようしています。
- 「transform: translateX(50%);」にて右側の位置に配置されるようにしている。
- 「opacity: 0;」で透過され見えない状態になっている。
「.is-show」が付与された時に以下のようにCSSが変化します。
- 「transform: translateX(0);」によって要素の50%右にずらしていたのを0にして元の位置に戻す。
- 「opacity: 1;」で見える状態に戻す。
- 「transition: all 0.75s ease-in-out 0.5s;」により、transformとopacityが0.75秒かけて「ease-in-out」でアニメーションされ、「.is-show」が付与されてから0.5秒遅れてアニメーションが始まる。
2. 「3番目の猫」 右から連続フェードイン
3枚並んでいる画像について、タイミングをずらしながら、順番に右から左にフェードインするアクションを入れます。
「transform」「opacity」「transition」を追加しています。
▼css/style.css
.item {
margin: 10px;
transform: translateX(50%);
opacity: 0;
}
.item:nth-child(1) {
/* プロパティ名 | 時間 | 時間関数 | 遅延 */
transition: all 0.75s ease-in-out 0.5s;
}
.item:nth-child(2) {
/* プロパティ名 | 時間 | 時間関数 | 遅延 */
transition: all 0.75s ease-in-out 0.75s;
}
.item:nth-child(3) {
/* プロパティ名 | 時間 | 時間関数 | 遅延 */
transition: all 0.75s ease-in-out 1s;
}
.list.is-show .item {
transform: translateX(0);
opacity: 1;
}
基本的には、「2番目の猫 右からフェードイン」と同じですが、「.item:nth-child(1)」では1番目の「.item」を、「.item:nth-child(2)」では2番目の「.item」というように別々にCSSを定義しており、transitonの遅延秒数を変えることによって、順番にアニメーションされるようにしています。
今回は0.5s→0.75s→1sと0.25s毎にアニメーションされるよう遅延設定しています。
3. 「4番目の猫」 下から連続フェードイン
3枚並んでいる画像について、タイミングをずらしながら、順番に下から上にふわっと浮いてくるようなフェードインするアクションを入れます。
「transform」「opacity」「transition」を追加しています。
▼css/style.css
.fadeitem {
margin: 10px;
transform: translateY(25%);
opacity: 0;
}
.fadeitem:nth-child(1) {
/* プロパティ名 | 時間 | 時間関数 | 遅延 */
transition: all 0.5s ease-in-out 0.5s;
}
.fadeitem:nth-child(2) {
/* プロパティ名 | 時間 | 時間関数 | 遅延 */
transition: all 0.5s ease-in-out 0.75s;
}
.fadeitem:nth-child(3) {
/* プロパティ名 | 時間 | 時間関数 | 遅延 */
transition: all 0.5s ease-in-out 1s;
}
.fadelist.is-show .fadeitem {
transform: translateY(0);
opacity: 1;
}
基本的には、「3番目の猫 右から連続フェードイン」と同じで、「translateX」だったものが「translateY」に変わっているだけです。
jQuery のJavaScript部分
▼script.js
$(function() {
// ①アニメーションさせる要素を取得
var $targetElements = $('.js-fade-animation');
// アニメーションさせる要素があるとき
if ($targetElements.length) {
// アニメーションさせる要素の高さを取得(複数ある場合を考えて配列で保存)
var fixedOffsets = $targetElements.map(function(index, element) {
return $(element).offset().top;
});
// windowを取得
var $window = $(window);
// ②画面の高さを取得
var windowHight = $window.height();
// ③resizeイベント
$window.on('resize', $.throttle(250, function() {
// 画面の高さを再取得
windowHight = $window.height();
// Offsetを再取得
fixedOffsets = $targetElements.map(function(index, element) {
return $(element).offset().top;
});
}));
// ④スクロールイベント
$window.on('scroll', $.throttle(250, function() {
// スクロール位置を取得
var scrollTop = $(this).scrollTop();
// .js-fade-animationの要素をすべてチェックする
fixedOffsets.each(function(index, offset) {
// ⑤アニメーションさせる要素の位置よりも下にスクロールされているとき
if (scrollTop + windowHight > offset) {
// ⑥要素をアニメーションさせる (.is-showを付与)
$targetElements.eq(index).addClass('is-show');
// ⑦アニメーション後は監視対象から外す
fixedOffsets.splice(index, 1);
$targetElements.splice(index, 1);
}
});
}));
}
});
コードについて解説します。
- ①アニメーションさせる要素を取得
「.js-fade-animation」Classが付いている要素はアニメーションさせる要素になるため、すべて取得します。 - ②画面の高さを取得
「$window.height();」つまり「$(window).height();」にて、ブラウザ画面の高さを取得しています。 - ③resizeイベント
ブラウザ画面のサイズ変更があった時に、画面の高さと要素のオフセット値を再取得しています。
また処理軽減のため、250msのthrottle処理を入れています。 - ④スクロールイベント
スクロールイベント処理を250msのthrottle処理を入れて処理しています。 - ⑤アニメーションさせる要素の位置よりも下にスクロールされているとき
スクロール時に、「if (scrollTop + windowHight > offset) {」として、画面内にアニメーションさせたい要素が入っているかを確認しています。
scrollTopは画面の上部の位置、それに画面の高さであるwindowHightを足して、画面の下の位置を算出しています。要素の位置であるoffsetと画面下の位置を比較して、画面内に要素が入っているかを判定しています。
- ⑥要素をアニメーションさせる (.is-showを付与)
画面内に入ったら、該当の「.js-fade-animation」要素に「.is-show」Classを追加します。 - ⑦アニメーション後は監視対象から外す
ここの処理はなくてもよいですが、アニメーション処理をして終了した後も、その要素をscrollイベントで監視したままになっています。
アニメーション処理が終わったブロックについては、scrollイベントでの監視から処理を外すために、「fixedOffsets」「$targetElements」の配列からアニメーション処理後に除外しています。
最終的なソースコードは、「complete」ディレクトリの内容になります。
スクロールでアニメーションする動作を実装したサンプルのURL
https://it-web-life.github.io/jquery_scroll_action_animation/complete/index.html
何度もアニメーションをさせたい場合
余談になりますが、スクロールにて一度アニメーション後、画面から外れて再度スクロールで画面内に入った際に、再度アニメーションさせたい場合、is-showのClassを画面から外れたら削除すれば実現できます。
(「⑦アニメーション後は監視対象から外す」としている処理を削除する必要もあります。)
// .js-fade-animationの要素をすべてチェックする
fixedOffsets.each(function(index, offset) {
// アニメーションさせる要素の位置よりも下にスクロールされているとき
if (scrollTop + windowHight > offset) {
// 要素をアニメーションさせる (.is-showを付与)
$targetElements.eq(index).addClass('is-show');
return;
}
// アニメーションさせる要素の位置よりも上のときは.is-showを削除
$targetElements.eq(index).removeClass('is-show');
});
まとめ
jQueryとCSSアニメーションを使って、スクロール動作に連動してアニメーションする実装を解説しました。
今回のコードのまとめは以下の通りです。
HTML:アニメーションさせたい要素に「.js-fade-animation」Classをつける
CSS:アニメーションさせたい要素に「.js-fade-animation」Classがついた時と、付く前のCSSを書く。
スクリプト:以下のscript.jsに書いているjQueryを書く
▼script.js
$(function() {
// アニメーションさせる要素を取得
var $targetElements = $('.js-fade-animation');
// アニメーションさせる要素があるとき
if ($targetElements.length) {
// アニメーションさせる要素の高さを取得(複数ある場合を考えて配列で保存)
var fixedOffsets = $targetElements.map(function(index, element) {
return $(element).offset().top;
});
// windowを取得
var $window = $(window);
// 画面の高さを取得
var windowHight = $window.height();
// resizeイベント
$window.on('resize', $.throttle(250, function() {
// 画面の高さを再取得
windowHight = $window.height();
// Offsetを再取得
fixedOffsets = $targetElements.map(function(index, element) {
return $(element).offset().top;
});
}));
// スクロールイベント
$window.on('scroll', $.throttle(250, function() {
// スクロール位置を取得
var scrollTop = $(this).scrollTop();
// .js-fade-animationの要素をすべてチェックする
fixedOffsets.each(function(index, offset) {
// アニメーションさせる要素の位置よりも下にスクロールされているとき
if (scrollTop + windowHight > offset) {
// 要素をアニメーションさせる (.is-showを付与)
$targetElements.eq(index).addClass('is-show');
// アニメーション後は監視対象から外す
fixedOffsets.splice(index, 1);
$targetElements.splice(index, 1);
}
});
}));
}
});
ご参考になれば幸いです。
※当サイトでは一部のリンクについてアフィリエイトプログラムを利用して商品を紹介しています