Terrarium

いわゆる掃き溜めの ありふれた有象無象

JavaScriptで要素をスクロール連動させたい時の基本知識

現在JavaScriptでWebサイトを作っている(そのうち公開予定)が,そこでスクロールによって画像背景をパララックス表示させたくなった.

その時にJavaScriptでスクロール連動させる時に使える値を色々調べたのでここにまとめようと思う. 今回はVue.jsを用いて作成しているが,jQueryでもその他でも使えるはず.

画面内での要素の位置

スクロール連動させる際には,スクロールによって変動する要素の座標的な値があると便利である. 画面内での,正確にはユーザの画面左上を原点とした要素の現在の位置は,getBoundingClientRect()により取得できる.

developer.mozilla.org

返されるオブジェクトがtopやleftといったkeyを持つため,それを指定することで要素の位置を知ることができる.

offsetTopもあるが,これは親要素からの相対的な位置なので,階層が深いdivに使うと思わぬ値が返って来たりする(これで詰まった…)

developer.mozilla.org

画面の大きさ

画面に現れた・画面から消えたなど画面に関わるスクロール連動を行う場合に必要になる. ユーザに表示されている画面の高さはwindow.document.documentElement.clientHeightによって取得ができる.

developer.mozilla.org

画面の幅はご想像の通り.

developer.mozilla.org

同じ分類の値としてoffsetHeightscrollHeightなどもあるが,clientHeightが一番使えるのではないだろうか.

stackoverflow.com

ちなみに,この画面の高さこれと先ほどを使うと,「要素が画面内に現れると同時に何かする」ことが可能になる.

qiita.com

上記ではjQueryを用いているが,全く同じ考え方で,Vue.jsなどで使う場合には次のようになる(下のコードは一応TypeScript).

handleScroll(evt: Event, el: HTMLElement) {
  if (windowHeight >= el.getBoundingClientRect().top) {
    // 要素の位置が画面内なら
    // 画面内にある時の処理
  } else {
    // 画面内にない時の処理
  }
}

スクロールした量

画面がどれだけスクロールされたかは,window.scrollYなどで取得できる. これは垂直方向だが,もちろん水平方向のスクロール量も取得できる.(もうわかると思うので省略)

developer.mozilla.org

取得が簡単なので,スクロールと連動してブラーがかかるなどが簡単に実装できる. cssfilterblurを設定している.

handleBlurScroll(evt: Event, el: HTMLElement) {
  el.style.webkitFilter = "blur(" + window.scrollY / 100 + "px)";
}

背景のパララックス実装

背景を前面の要素より遅く動かすと格好いいことが知られている(要出典).

↓こんなイメージ.

pixelcog.github.io

実装のためには背景を遅れて動作させればいいわけだが,csstransformを使うと要素の位置を動かすことができる. これをスクロールによって変化した値に依存させて適用すれば,スクロールから遅れて背景を動かすことができる.

実装してみた例がこちら. このコードをイベントハンドラとしてスクロールの度に呼び出す.

handleParallaxScroll(evt: Event, el: HTMLElement) {
  let windowHeight = window.document.documentElement.clientHeight;
  let elementTop = el.getBoundingClientRect().top;
  if (windowHeight >= elementTop) {
    // 画面内にあるなら要素の画面内Y座標の半分だけ上にずらす
    el.style.transform = "translateY(" + -1 * (elementTop / 2) + "px)";
  }
},

「基準要素の画面内座標の半分だけ上にずら」しているが,ここは色々な実装が考えられる. こうすることで,画面いっぱいの要素を上から下までスクロールするとちょうど画像の全景が確認できるようにしている. 自身の要素しか参照していないため,複数のdivに対してこのハンドラを結びつけても動作させることができる.

終わりに

だいぶ格好いいパララックスが実装でき満足している. そのうち実装したWebサイトを公開します.

f:id:tellusium:20190115204616g:plain