JavaScript

【サンプルあり】スクロール途中でヘッダーを固定させる方法2選

スクロールの途中でヘッダーを固定させる方法を2つ紹介します。

JavaScriptとCSSで実装する方法と、CSSのみで実装する方法があります。

共通HTML

HTMLは共通です。pタグ内のテキスト部分は長いので省略しています。

<div class="container">
  <div class="hero">
    Scroll Down
  </div>
  <header class="header">
    Header
  </header>
  <main class="main">
  <p>略...</p>
  </div>
</div>

JavaScriptとCSSで実装する方法

サンプル

スクロール位置がヘッダーに差し掛かると、ヘッダーに対して.fixedというクラスをJavaScriptで追加しています。

See the Pen Scroll Header (JS & CSS) by POSIPAN (@posipan) on CodePen.

CSS

ポイントとなる部分を抜粋しています。

.fixedposition: fixed;により、ヘッダーが固定されます。

また、.fixedが追加されると、main要素に対してpadding-top(ヘッダーの高さ + mainpadding-topの値)を設定しています。

これはヘッダーが固定モードになる際のカクツキを防ぐためです。
試しにpadding-topを削除してみると良いでしょう。

header {
  background: #bbb;
  width: 100%;
  height: 60px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  // .fixedを追加した時のCSS
  &.fixed {
    position: fixed;
    top: 0;
    + main {
      padding-top: 75px;
    }
  }
}

.main {
  padding: 15px;
  max-width: 600px;
  margin: 0 auto;
  line-height: 2;
}

JavaScript

変数fixedにページの最上部からヘッダーまでの座標位置(px)を格納しています。

fixHeader関数の中で、スクロールによって変化するwindow.pageYOffsetの値と変数fixedの値を比較しています。

その結果によって、headerに対してクラス.fixedの追加・削除を行なっています。

window.addEventListener('scroll', fixHeader);

const header = document.querySelector('.header');

// ヘッダーの座標位置
let fixed = header.getBoundingClientRect().top + window.pageYOffset;

function fixHeader() {
  // スクロール量がヘッダーの座標位置を超えた時に.fixedを追加
  if (window.pageYOffset > fixed) {
    header.classList.add('fixed');
  } else {
    header.classList.remove('fixed');
  }
}

Element.getBoundingClientRect()

ブラウザ表示領域の左上(0, 0)からElementまでの相対座標位置を取得するメソッドです。

このメソッドは下記のようなプロパティを持っています。

  • top – 要素の上端のY座標
  • left – 要素の左端のX座標
  • right – 要素の右端のX座標
  • bottom – 要素の下端のY座標

本サンプルではtopプロパティを使用して、Element.getBoundingClientRect().topでブラウザ表示領域上端からヘッダー上端までのY座標を取得しています。

出典: https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect

window.pageYOffsetとは?

pageYOffsetはwindowのプロパティであり、垂直方向のスクロール量を取得できます。

また、本サンプルでは下記のようにElement.getBoundingClientRect().topと組み合わせることでElementの絶体座標を取得することができます。

絶体座標とはページ(ドキュメント)の左上からElementまでの座標位置のことです。

let fixed = header.getBoundingClientRect().top + window.pageYOffset;

CSSのみで実装する方法

サンプル

position: sticky;でヘッダーを固定しています。

See the Pen Scroll Header (CSS Only) by POSIPAN (@posipan) on CodePen.

CSS

ポイントとなる部分を抜粋しています。

先程のJS&CSS実装版との違いは、&.fixed〜の箇所を削除し、position: sticky;top: 0;を追加している点です。

position: sticky;を指定した要素は要素分の高さを保持しつつ、ブラウザ領域の上端に差し掛かったところで要素が固定されます。

header {
  background: #bbb;
  width: 100%;
  height: 60px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  // 下記を追加
  position: sticky;
  top: 0;
}

position: sticky;とは?

簡単に言うと、positionのrelative、absolute、fixedの機能を合わせ持つ値です。

今回のようにスクロール途中から要素を固定させることができます。

とてもわかりやすい記事がありましたので、こちらを参考にすると理解が深まります。

https://www.asobou.co.jp/blog/web/css-sticky

おわりに

CSSのみで実装する方が圧倒的に楽でしたね!

position: sticky;はIE11以下では非対応ですが、
IE11以下に対応する案件自体、減少傾向にあるので気にせず使えそうですね。

ではまた!