JavaScript

スクロールに応じた視差(パララックス)効果のある動きをJavaScriptライブラリなしで実装

スクロールしたとき、普通なら画面全体が同じように動きますが、部分的に他とは違う動きをつけると、視差効果で奥行きが感じられ、デザインとして深みを感じてもらえるようになると思います。ライブラリもありますが、簡単に実装できる方法がありますのでご紹介したいと思います。

視差効果(パララックス)とは

奥行きがある場合、手前のものとそれより奥にあるものとでは、同じだけ前に進んだときに視野に入る動きが異なります。それにより、視覚的に奥行きを感じることができます。

ディスプレイ上に表示されているものは実際には奥行きがないわけですが、スクロールしたときに、画面全体の動きと異なる動きをつけると、視差効果で深みのあるデザイン表現ができます。

デモ

スクロールして、下の矩形の動きを確認ください。

スクロールに応じて、縦の位置を変化させていて、3つそれぞれで、移動の大きさを変えることで視差効果が生まれ、奥行きを感じる動きになります。

コード

このページでデモするために、このページに合わせて作成したコードそのままですが、ご紹介します。

HTML

<div class="demo-wrapper">
   <div id="box-01"></div>
   <div id="box-02"></div>
   <div id="box-03"></div>
</div>

CSS

.demo-wrapper{
   position: relative;
   width: 100%;
   height: 1000px;
   background-color: #f1f1f1;
}
#box-01, #box-02, #box-03{
   position: absolute;
   width: 150px;
   height: 150px;
   transition: 1s;
}
#box-01{
   top: 52%;
   left: calc(50% - 100px);
   transform: translate(-50%, -50%);
   background-color: rgba(201, 231, 29, 0.7);
}
#box-02{
   top: 50%;
   left: 50%;
   background-color: rgba(118, 190, 77, .7);
   transform: translate(-50%, -50%);
}
#box-03{
   top: 48%;
   left: calc(50% + 100px);
   transform: translate(-50%, -50%);
   background-color: rgba(77, 190, 152, .7);
}

JavaScript

<script>
const box_wrapper = document.querySelector('.demo-wrapper'); 
const box_01 = document.getElementById('box-01');
const box_02 = document.getElementById('box-02');
const box_03 = document.getElementById('box-03');
   
window.addEventListener('load', parallax);
window.addEventListener('resize', parallax);
window.addEventListener('scroll', parallax, { passive: true });
let timer = null;

function parallax(){
   clearTimeout( timer );
   timer = setTimeout (function() {
   const scrollTop = box_wrapper.getBoundingClientRect().top;
   if(scrollTop > 150){
      box_01.style.top = '50%';
      box_02.style.top = '52%';
      box_03.style.top = '48%';
      box_01.style.transform = 'translate(-50%, -50%) scale(1)';
      box_02.style.transform = 'translate(-50%, -50%) scale(1)';
      box_03.style.transform = 'translate(-50%, -50%) scale(1)';
   }else if(scrollTop < 150){
      box_01.style.top = '40%';
      box_02.style.top = '46%';
      box_03.style.top = '28%';
      box_01.style.transform = 'translate(-50%, -50%) scale(.8)';
      box_02.style.transform = 'translate(-50%, -50%) scale(.9)';
      box_03.style.transform = 'translate(-50%, -50%) scale(.7)';
   }else if(scrollTop < -200){
      box_01.style.top = '30%';
      box_02.style.top = '40%';
      box_03.style.top = '8%';
      box_01.style.transform = 'translate(-50%, -50%) scale(.7)';
      box_02.style.transform = 'translate(-50%, -50%) scale(.85)';
      box_03.style.transform = 'translate(-50%, -50%) scale(.6)';
   }else if(scrollTop < -500){
      box_01.style.top = '50%';
      box_02.style.top = '52%';
      box_03.style.top = '48%';
   }
}, 10);
}
</script>

解説

JavaScriptでは、各矩形の高さ方向の位置と大きさについて、スクロール位置によって変えるということをしています。スクロール位置は外枠のdiv要素を基準にしてgetBoundingClientRect()を用いて取得しています。その位置に応じて、CSSを操作するプロパティelement.styleを用いて位置と大きさを指定しているだけです。
その位置までスムーズに変化する動きは、CSSのtransitionでつけています。
なので、比較的簡単に実装できます。

なお、このデモでは分かりやすくするため大きさまで変えてますが、高さ方向の位置を変えるだけでも動きのある感じにはなりますので、ちょっとデザインに深みを持たせるのには十分かもしれません。

今後はCSSだけでも実装可能に

現在仕様策定が進んでいて草案となっているCSSの「Scroll-driven Animations」によって、今後はCSSだけでもパララックスが実装可能となります。

すでにChrome115以降およびChrome115以降が中身に使われているEdgeは対応しています。次の記事で詳しく解説しています。

CSSだけでスクロールアニメーション!Scroll-driven Animations、animation-timelineプロパティを解説

ただし、Scroll-driven Animationsはスクロールと連動した動きしか実装できず、スクロールを止めると動きも止まってしまいますので、JavaScriptによる実装との使い分けになると考えています。

まとめ

ライブラリなしでも簡単にパララックス効果をつけることができますというご紹介でした。このような動きをうまくつけていくことで、ちょっとリッチな雰囲気を出すことができますので是非お試しください。

著者のイメージ画像

株式会社BringFlower
稲田 高洋(Takahiro Inada)

2003年から大手総合電機メーカーでUXデザインプロセスの研究、実践。UXデザイン専門家の育成プログラム開発。SEOにおいても重要なW3Cが定めるWeb標準仕様策定にウェブアクセシビリティの専門家として関わる。2010~2018年に人間中心設計専門家を保有、数年間ウェブアクセシビリティ基盤委員も務める。その後、不動産会社向けにSaaSを提供する企業の事業開発部で複数サービスを企画、ローンチ。CMSを提供し1000以上のサイトを分析。顧客サポート、サイト運営にも関わる。
2022年3月にBringFlowerを開業し、SEOコンサル、デザイン、ウェブ制作を一手に受ける。グッドデザイン賞4件、ドイツユニバーサルデザイン賞2件、米国IDEA賞1件の受賞歴あり。
プロフィール詳細