スクロールで高さが変化するヘッダの実装方法

スクロールで変化するヘッダの実装方法

この記事ではスクロールしたときに高さの変化するヘッダの実装方法を解説します。高さに限らずスクロールに応じて要素のデザインを変えたい場合にも応用可能ですよ。JavaScript部分にフォーカスして説明しているので、JavaScriptが苦手な方はぜひご一読ください!

目次

サンプルページの解説

わかりやすく説明するために、サンプルページを用意しました。

See the Pen Scroll-Responsive Header & Sticky Sidebar by Aizawa Web Design (@AizawaWebDesign) on CodePen.

サンプルページには以下の動きが付いています。

  • スクロールするとヘッダがコンパクトになる
  • ヘッダの高さの変化に対応して下のコンテンツに余白を入れる
  • ページトップに戻ったときはヘッダも元の表示に戻る

実はこのWebサイトのヘッダもPC表示のときには同様の動きを付けています。タイトル部分がけっこう大きいので、邪魔にならないようにスクロール時はナビゲーションバー部分だけを表示しています。

なお、サンプルページのHTMLとCSS部分は以下の記事で詳しく紹介しているので、気になる方はぜひ併せてご覧ください!

ヘッダを変化させるためのJavaScriptコード全容

ではさっそくJavaScriptのコード全体を見てみましょう。

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

function updateLayoutOnScroll() {
  const scrollY = window.scrollY;

  if (scrollY > 1) {
    if (!header.classList.contains('header--compact')) {
      header.classList.add('header--compact');
      
      const compactHeight = header.offsetHeight;

      if (container) {
        container.style.paddingTop = `${compactHeight}px`;
      }
    }
  } else {
    if (header.classList.contains('header--compact')) {
      header.classList.remove('header--compact');

      if (container) {
        container.style.paddingTop = '';
      }
    }
  }
}

window.addEventListener('scroll', updateLayoutOnScroll);
window.addEventListener('load', updateLayoutOnScroll);
window.addEventListener('resize', updateLayoutOnScroll);
JavaScript

ページがスクロールされるとheader.header--compactというクラスを付けて、クラスが付いたときのスタイルをCSS上で調整(今回の場合、サイト名を非表示にしてナビゲーションバーのみ表示)しています。

反対にスクロールでページの上まで戻ってきたときは.header--compactクラスを外して、元の表示に戻すというシンプルな仕組みです。

ほかにもいくつか細かな調整をしているので、その点も含めてもう少し詳しく紹介していきますね。

スクロールに応じたクラスの付け外し

以下の部分でまず「スクロールされたらクラスを付ける」という指示を出しています。

if (scrollY > 1) {
    if (!header.classList.contains('header--compact')) {
      header.classList.add('header--compact');
JavaScript

scrollYという変数でwindow.scrollYの値を呼び出しています。

  • window.scrollY=今どのくらいスクロールされているか(px)

つまり、上記コードの1行目は「スクロール量が1pxを超えたら(少しでもスクロールされたら)」ということです。

その場合に、classList.addによってheaderheader--compactというクラス名を付けています。

また、elseに続く部分で、スクロール位置が1pxを超えないとき=ページのほぼ一番上に戻ってきたときにはclasslist.removeで先ほど付けたクラス名を外すように指示を出しています。

} else {
    if (header.classList.contains('header--compact')) {
      header.classList.remove('header--compact');
JavaScript

あとは.header--compactに対してCSSで希望するスタイルをあてれば、スクロールによって変化するヘッダの基礎部分は完成です!

ヘッダの高さによって続くコンテンツの上部余白を調整する

ちょっとわかりづらい見出しになってしまいました…

今回のサンプルページはヘッダの下に固定サイドバーがあります。そのため、ヘッダの高さが変化したときは、ヘッダの高さが小さくなった分だけサイドバーが上にずれてしまっていました。

そこで、サイドバーを含む.containerに対して、変化したあとのヘッダの高さ分、上部に余白を追加することにしました。

const compactHeight = header.offsetHeight;
if (container) {
  container.style.paddingTop = `${compactHeight}px`;
}
JavaScript
  • offsetHeight=要素の見た目の高さ(px)

ここでは要素=headerの見た目の高さをリアルタイムに取得して、その値が.containerの上部のpaddingに追加されるようにしています。

container.style.paddingTopの部分は、containerという要素のCSSにおけるpadding-topプロパティをJavaScriptから直接変更して!という意味ですね。

こうすることで、ヘッダの高さが変わってもサイドバーとヘッダの位置関係が変わらないように調整されています。

調整されたレイアウトを維持する工夫

最後に、レイアウト崩れを防ぐため、いつこの一連の処理を実行するかを設定(=イベント登録)します。

window.addEventListener('scroll', updateLayoutOnScroll);
window.addEventListener('load', updateLayoutOnScroll);
window.addEventListener('resize', updateLayoutOnScroll);
JavaScript

ここでは「スクロールに応じてヘッダなどのレイアウトを変化させる」という動きを、addEventListenerを使ってscrollloadresizeというイベントが起こるたびに実行して、という指示を書いています。

いずれのイベントもヘッダの高さに関わるため、これらを書いておくことで最初からスクロールされた状態(例えばリンクでページ下部に飛んできたときなど)で表示された場合や、ウィンドウのサイズが変わった場合でもレイアウトが崩れにくくなります。

ちなみによく使われるイベントには次のようなものがあります。

scrollページがスクロールされたとき
loadページの読み込みが完了したとき
resizeウィンドウサイズが変わったとき
click要素がクリックされたとき
inputフォームの値が変わったとき

これらを使い分ければ、スクロール以外のイベントに連動した動作も実装できますね。

まとめ

スクロールに応じてヘッダのデザインを変化させることでコンテンツがより見やすくなり、ユーザの使い勝手も向上する場合がありますよね。今のデザインだとヘッダがちょっと邪魔…というときにはぜひこの記事を参考にしていただけたら嬉しいです。

関連タグ