【更新日 : 】
【JavaScript】Intersection Observer + scrollイベントでパララックスを実装する
- Category:
- JavaScript
- Tags:
- JavaScript, transition, Vanilla JS, アニメーション, パララックス, レイアウト, 脱Jquery, 自作関数
Intersection Observer + scrollイベントでパララックスを実装したサンプルです。
画面に入った要素のみscrollイベントを発火させるので、scrollイベントのみの実装よりは低負荷になっていると思います。
※以前実装した以下のコードをベースにしています。
動作サンプル
表示エリアからはみ出している量だけ画像が動きます。
スクロール中に要素がエリアから飛び出さないように動く量はウィンドウの高さに応じて算出しています。
<p class="codepen" data-height="500" data-default-tab="result" data-slug-hash="gOjOPjd" data-user="web_walking_nak" style="height: 500px; 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/web_walking_nak/pen/gOjOPjd">
Intersection Observer + Scroll Event Parallax Vanilla JS</a> by web_nak (<a href="https://codepen.io/web_walking_nak">@web_walking_nak</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
HTML
表示エリア .js-parallax-elm-box
の中に、動かす要素 .js-parallax-elm
を内包してください。
上記は画像を格納していますが、何が入っていても動きます。
<div class="js-parallax-elm-box">
<div class="js-parallax-elm">
<img src="画像パス" alt="">
</div>
</div>
CSS
表示エリアからはみ出している要素を隠すため、最低限overflow: hidden;を設定してください。
※表示エリアのheightは実装するデザインに応じて適宜設定してください。
.js-parallax-elm-box {
overflow: hidden;
}
.js-parallax-elm-box img {
display: block;
}
JavaScript
対象class名を変更したい場合は、targetClass
「表示エリア class」と、childClass
「動かす要素 class」を編集してください。
//Intersection Observer + Scroll Event Parallax Vanilla JS
function parallax() {
'use strict';
//class設定
//表示エリア class
const targetClass = '.js-parallax-elm-box';
//動かす要素 class
const childClass = '.js-parallax-elm';
//表示エリア取得
const targets = Array.prototype.slice.call(document.querySelectorAll(targetClass),0);
//表示エリアが存在するかチェック
if(targets.length === 0) {
return;
}
//observer設定
let observer = new IntersectionObserver(observerFunc, {
root: null,
rootMargin: '0px',
threshold: 0
});
//ウィンドウの高さ取得
let winH = window.innerHeight;
//スクロール量(ウィンドウの上端)取得
let scrollTop = window.pageYOffset || document.documentElement.scrollTop;
//スクロール量(ウィンドウの下端)取得
let scrollBottom = scrollTop + winH;
//初期設定
let setListener = [];
let settings = [];
targets.forEach((target,index) => {
//Listener設定取得用の判別番号をセット
target.setAttribute('data-index',index);
//動かす要素を取得
const child = target.querySelector(childClass);
//動かす要素が存在するかチェック
if(!child) {
return;
}
//処理用の設定を追加
settings.push({
child: child,
//比率取得:スクロールできる最大量 / (ウィンドウの高さ + 表示エリアの高さ)
scrollRatio: (child.clientHeight - target.clientHeight) / (winH + target.clientHeight)
});
//scrollイベントへ渡すlistener設定
setListener.push(
{
target: target,
handleEvent: function handleEvent () {
requestAnimationFrame(parallaxFunk.bind(target));
}
}
);
//初期表示の位置調整
requestAnimationFrame(parallaxFunk.bind(target));
//observer監視開始
observer.observe(target);
});
//高さ更新
let resizeID;
window.addEventListener('resize', function() {
clearTimeout(resizeID);
resizeID = setTimeout(() => {
//ウィンドウの高さ取得
winH = window.innerHeight;
//各要素の高さ更新
targets.forEach((target,index) => {
//動かす要素が存在するかチェック
if(!settings[index].child) {
return;
}
//比率取得:スクロールできる最大量 / (ウィンドウの高さ + 表示エリアの高さ)
settings[index].scrollRatio = (settings[index].child.clientHeight - target.clientHeight) / (winH + target.clientHeight);
});
}, 200);
});
//スクロール量更新
window.addEventListener('scroll', function() {
//スクロール量(ウィンドウの上端)取得
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
//スクロール量(ウィンドウの下端)取得
scrollBottom = scrollTop + winH;
}, {passive: true});
//observer処理
function observerFunc(entries) {
entries.forEach(entry => {
//listener設定取得
const listener = setListener[entry.target.getAttribute('data-index')];
if(entry.isIntersecting) {
//画面に表示されている要素のみスクロールイベントへ追加
window.addEventListener('scroll', listener, {passive: true});
} else {
//画面外のときはスクロールイベント削除
window.removeEventListener('scroll', listener, {passive: true});
}
});
}
//パララックス位置調整関数
function parallaxFunk() {
//番号取得
const index = Number(this.getAttribute('data-index'));
//表示エリアの位置取得
const targetPosi = this.getBoundingClientRect().top + scrollTop;
//ウィンドウの高さに対するスクロール量を取得(小数点第2以下は四捨五入)
const setVal = ((scrollBottom - targetPosi) * settings[index].scrollRatio).toFixed(1);
//スクロール値を設定
settings[index].child.style.transform = 'translate3d(0,'+ (setVal * -1) +'px,0)';
}
}
関数の呼び出し
任意の場所で以下を実行し関数を呼び出してください。
//パララックス呼び出し
parallax();
関連リンク
- 【JavaScript】Intersection Observer + requestAnimationFrameでパララックスを実装する
- 【脱Jquery】Vanilla JSでシンプルなパララックスを実装する