🙌

スクロールすると表示・非表示が切り替わるヘッダーのテンプレート | HTML, CSS(SCSS), JS

2024/09/18に公開

概要

スクロールすると表示・非表示が切り替わるヘッダーのテンプレート. 下にスクロールすると、ヘッダーが画面上部に消えていって、上にバックスクロールすると、ヘッダーが画面上部から出現する
よく使うのでテンプレートにしました
サンプルページ

前提

ファイル構造

/
├ logo-256x512.png
├ index.html
├ style.css
└ script.js

コード

HTML / index.html

index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Sample</title>
  <link rel="stylesheet" href="./style.css">
  <script src="./script.js"></script>
</head>
<body>
<!-- ここから -->
  <header>
    <div class="header-wrap">
        <div class="header-logo">
            <a href="#">
                <img src="./logo-256x512.png" alt="Sample Header Logo Image" />
            </a>
        </div>
        <div class="header-menu">
            <nav>
                <li><a href="#">メニュー1</a></li>
                <li><a href="#">メニュー2</a></li>
            </nav>
        </div>
    </div>
  </header>
<!-- ここまでが必要 -->
</body>
</html>

CSS / style.css

style.css
* {
  margin: 0;
  padding: 0;
  box-sizing: content-box;
}

header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  background-color: black;
  height: 50px;
}
header * {
  transition: 0.4s;
}
header li, header a {
  list-style: none;
  color: white;
  text-decoration: none;
}
header.hide {
  animation: headerFadeOut 1s;
  opacity: 0;
}
header.show {
  opacity: 1;
  animation: headerFadeIn 1s;
}

.header-wrap {
  height: 100%;
  display: flex;
}

.header-logo, .header-logo * {
  height: 100%;
}
.header-logo a {
  display: flex;
  align-items: center;
  text-align: center;
}
.header-logo a:hover {
  opacity: 0.6;
}

.header-menu {
  flex-grow: 10;
  display: flex;
  justify-content: space-between;
}
.header-menu nav {
  display: flex;
}
.header-menu li {
  display: flex;
  align-items: center;
  margin: 0 0.5rem;
}
.header-menu a:hover {
  opacity: 0.6;
}

@keyframes headerFadeOut {
  0% {
    opacity: 1;
    top: 0;
  }
  100% {
    opacity: 0;
    top: -100%;
  }
}
@keyframes headerFadeIn {
  0% {
    top: -100%;
  }
  100% {
    top: 0;
  }
}/*# sourceMappingURL=style.css.map */

SCSS からコンバートしたもの. ソースは以下

SCSS ソースコード
style.scss
@charset "UTF-8";

// ヘッダーの表示・非表示アニメーションにかける時間
$HEADER-ANIMATION-DURATION: 1s;
// ヘッダーの高さ
$HEADER-HEIGHT: 50px;

* {
    margin: 0;
    padding: 0;
    box-sizing: content-box;
}

header {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    background-color: black;
    height: $HEADER-HEIGHT;
    * {
        transition: .4s;
    }

    li, a {
        list-style: none;
        color: white;
        text-decoration: none;
    }
    
    &.hide {
        animation: headerFadeOut $HEADER-ANIMATION-DURATION;
        opacity: 0;
    }
    &.show {
        opacity: 1;
        animation: headerFadeIn $HEADER-ANIMATION-DURATION;
    }
}

.header-wrap {
    height: 100%;
    display: flex;
}

.header-logo {
    &, * {
        height: 100%;
    }
    a {
        display: flex;
        align-items: center;
        text-align: center;
        &:hover {
            opacity: .6;
        }
    }
}

.header-menu {
    flex-grow: 10;
    display: flex;
    justify-content: space-between;

    nav {
        display: flex;
    }
    li {
        display: flex;
        align-items: center;
        margin: 0 .5rem;
    }
    a {
        &:hover {
            opacity: .6;
        }
    }
}

@keyframes headerFadeOut {
    0% {
      opacity: 1;
      top: 0;
    }
    100% {
      opacity: 0;
      top: -100%;
    }
}

@keyframes headerFadeIn {
    0% {
        top: -100%;
    }
    100% {
        top: 0;
    }
}

JS / script.js

script.js
const CONSTS = {
    /** 
     * ヘッダーの表示・非表示アニメーションにかける時間
     * style.scss の HEADER-ANIMATION-DURATION と同じ秒数を指定する
     * @type {Number} 単位: ミリ秒
     */
    HEADER_ANIMATION_DURATION: 1000,
    /**
     * ヘッダーの高さ
     * style.scss の HEADER-HEIGHT と同じ高さを指定する
     * @type {Number} 単位: px
     */
    HEADER_HEIGHT: 50,
}

/**
 * スクロールしたら呼び出される
 * @param {Number} scrolled スクロール時のページ上部からの高さ
 * @param {Number} previousScroll 前回の scrolled 値
 */
function onScroll(scrolled, previousScroll) {
    const hd = document.querySelector('header');

    // スクロール量がヘッダーの高さ未満のとき: ヘッダーは画面固定しない
    if (scrolled <= CONSTS.HEADER_HEIGHT) {
        if (hd.style.position !== 'absolute') hd.style.position = 'absolute';
        if (hd.style.top !== '0') hd.style.top = '0';
    }
    // 下にスクロールしたとき: ヘッダーを非表示にする
    else if (scrolled > previousScroll) {
        if (hd.classList.contains('show')) hd.classList.remove('show');
        if (!hd.classList.contains('hide')) hd.classList.add('hide');
    }
    // 上にバックスクロールしたとき: ヘッダーを表示する
    else {
        // 要素に付与されたスタイルはリセット
        hd.style.top = '';
        hd.style.position = '';
        
        if (hd.classList.contains('hide')) hd.classList.remove('hide');
        if (!hd.classList.contains('show')) hd.classList.add('show');
    }
}

// DOM の読み込みが完了したら読み込まれる
document.addEventListener('DOMContentLoaded', () => {
    // スクロール時に onScroll 関数を実行する
    let previousScroll = 0;
    let scrolled = 0;
    window.addEventListener("scroll", async () => {
        previousScroll = scrolled;
        scrolled = window.pageYOffset
        onScroll(scrolled, previousScroll);
    });
});

注意点

CSS と JS で共通の値を設定すべきところがあります. しかし、このテンプレートの CSS は SCSS をコンバートしたものなので、その値を設定するときは SCSS を編集して再びコンバートしてください.
設定すべきところ:

  • JS の HEADER_ANIMATION_DURATION と SCSS の $HEADER-ANIMATION-DURATION
  • JS の HEADER_HEIGHT と SCSS の $HEADER-HEIGHT

また、コンテンツを作成するとき、header 要素の position が absolute や fixed になることに注意して下さい. コンテンツが header 要素の下にいったり、後ろにいったりします. 適宜調整が必要です

Discussion