👻

[JavaScript]素のJSで作る追従バナーサンプル

2022/12/12に公開約2,600字

はじめに

本記事は、筆者による理解の復習・確認やアウトプットの練習のために書いております。
間違った解釈等ございましたら、ご連絡いただけますと幸いです。

イメージ


動画 →GIF 変換のせいか、気持ち速くなってます

確認動作環境

Chrome

コード置き場

https://github.com/haya573/floating-banner-js-sample

コード全体

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>追従バナーサンプル</title>
</head>
<body>
  <div id="banner-wrapper"></div>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    body {
      height: 2000px;
      position: relative;
    }
    #banner-wrapper {
      width: 150px;
      height: 150px;
      background: red;
      position: absolute;
      right: 0;
      background: url(./banner.png);
      background-size: contain;
    }
  </style>
  <script>
    const banner = document.getElementById('banner-wrapper')
    const bannerHeight = banner.offsetHeight
    const windowHeight = window.innerHeight
    const displayHeight = windowHeight - (bannerHeight + 30)

    banner.style.top = `${displayHeight}px`
    banner.style.bottom = 'initial';

    window.addEventListener('scroll', () => {
      const scrollY = document.documentElement.scrollTop
      banner.style.top = `${displayHeight + scrollY}px`

      banner.animate([
        { top: `${displayHeight + scrollY}px` }
      ], {
        duration: 2000,
        easing: 'ease-in-out'
      })
    })
  </script>
</body>
</html>

それぞれ説明

  const banner = document.getElementById('banner-wrapper') // 要素の取得
  const bannerHeight = banner.offsetHeight // 要素の高さを取得(150px)
  const windowHeight = window.innerHeight // 表示されている画面の高さを取得
  const displayHeight = windowHeight - (bannerHeight + 30) // バナーの定位置を初期値として設定
  banner.style.top = `${displayHeight}px` // バナーの定位置をスタイルに反映

ちなみに、↑ を設定しなくても追従するんですが、たまに挙動がおかしくなってバナーがどこか行ってしまうので、スクロールのたびに top 値を設定してます。

  // スクロールした時に発火
  window.addEventListener('scroll', () => {
    const scrollY = document.documentElement.scrollTop // スクロールしたピクセル数を返す
    banner.style.top = `${displayHeight + scrollY}px` // バナー定位置 + スクロール分をtopの値に設定

    // ぬるっと動かすアニメーションの設定
    banner.animate([
        { top: `${displayHeight + scrollY}px` }
    ], {
      duration: 2000, // 2000ミリ秒(2秒)遅らせてアニメーションさせる
      easing: 'ease-in-out' // 最初と最後だけゆっくり、中間は加速する動きをつける
    })
  })

最後に

スクロールするたびに top 値を設定するの、処理が重くなってそうで嫌だなと思いながらも
他に実装手法を思い浮かばないので、もっと良い実装方法ございましたら教えてください!

参考

https://developer.mozilla.org/ja/docs/Web/API/Element/scrollTop
https://developer.mozilla.org/ja/docs/Web/API/Element/animate

GitHubで編集を提案

Discussion

ログインするとコメントできます