上毛印刷株式会社

【JavaScript】ハンバーガーメニュー中にスクロールさせない

【JavaScript】ハンバーガーメニュー中にスクロールさせない

2023年09月26日
WEBサイト制作
  • #HTML
  • #css
  • #JavaScript
  • #tips

こんにちは!
上毛印刷WEB制作担当のソーヤです。

結構クライアントから要望の多い仕様の実装方法をご紹介します!
特にスマホで起こる現象なのですが、
ハンバーガーメニューを開いてる最中に意図せずスクロールしてしまって、
メニューを開く前の画面と位置が違うという誤操作を防ぐための対策です。

今回の実装例は少し特殊なので、デモページを作成しました。
アクセスしてみてください。
デモページはこちら(別タブで開きます)

HTML例

<div class="l-wrapper">
    <header class="l-header">
        <div class="l-header__inner">
          <p class="l-header__text">ここをクリック→</p>
            <div class="gnav-btn">
            <div class="icon-animation">
                <span class="top"></span>
                <span class="middle"></span>
                <span class="bottom"></span>
            </div>
            </div>
            <nav class="l-nav">
            <ul class="l-nav__list u-flexWrap">
                <li class="l-nav__item">
                <a href="/blog/javascript-dont-let-it-scroll-during-hamburger-menu/">企業情報</a>
                </li>
                <li class="l-nav__item">
                <a href="/blog/javascript-dont-let-it-scroll-during-hamburger-menu/">グループ企業情報</a>
                </li>
                <li class="l-nav__item">
                <a href="/blog/javascript-dont-let-it-scroll-during-hamburger-menu/">グループ事業紹介</a>
                </li>
                <li class="l-nav__item">
                <a href="/blog/javascript-dont-let-it-scroll-during-hamburger-menu/">IR情報</a>
                </li>
                <li class="l-nav__item">
                <a href="/blog/javascript-dont-let-it-scroll-during-hamburger-menu/">サステナビリティアクション</a>
                </li>
                <li class="l-nav__item">
                <a href="/blog/javascript-dont-let-it-scroll-during-hamburger-menu/">ニュースリリース</a>
                </li>
                <li class="l-nav__item">
                <a href="/blog/javascript-dont-let-it-scroll-during-hamburger-menu/" target="_blank">採用情報</a>
                </li>
            </ul>
          </nav>
        </div>
    </header>
</div>

CSS例

body{
  height: 10000px;
}
.l-header{
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 60px;
  z-index: 200;
  background-color: #fff;
  transition: 0.4s ease;
}
.l-header__inner{
  width: 100%;
  height: 100%;
}
.l-header__text{
  text-align: right;
  padding: 0 60px 0 0;
}
.l-header__list{
  position: absolute;
  top: 40px;
  right: 0;
  transition: 0.4s ease;
}
.l-header__item{
  box-sizing: border-box;
  padding: 0 30px;
  border-right: 1px solid #c8c8c8;
}
.l-header__item:last-of-type{
  padding: 0 0 0 30px;
  border-right: none;
}
.l-header__item a{
  color: #000;
  font-size: 14px;
  transition: 0.4s ease;
}
.l-header__item a:hover{
  opacity: 0.7;
}
.l-nav{
  width: 100%;
  zoom: 1;
  position: absolute;
  bottom: 0px;
  height: 70px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 101;
  transition: 0.4s ease;
}
.l-nav__list{
  justify-content: center;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  margin: auto;
  list-style: none;
}
.l-nav__item{
  box-sizing: border-box;
  border-bottom: 0px solid transparent;
  transition: 0.2s ease;
  height: 70px;
}
.l-nav__item > a{
  font-size: 16px;
  color: #fff;
  height: 70px;
  display: -webkit-flex;
  display: -ms-flex;
  display: flex;
  align-items: center;
  padding: 22.5px;
  font-weight: 500;
  transition: 0.1s ease;
  box-sizing: border-box;
  white-space: nowrap;
}
.l-nav{
  height: auto;
  top: 60px;
  left: auto;
  transform: translateX(100%);
}
.l-nav__item{
  height: 50px;
}
.l-nav__item > a{
  font-size: 15px;
  height: 50px;
  display: -webkit-flex;
  display: -ms-flex;
  display: flex;
  align-items: center;
  padding: 0 0 0 22px;
  position: relative;
  background-color: #000;
  color: #fff;
  border-bottom: 1px solid #fff;
}
.l-nav__item > a::before,
.l-nav__item > a::after {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  margin: auto;
  content: "";
  vertical-align: middle;
  transition: 0.4s ease;
}
.l-nav__item > a::after {
  left: auto;
  right: 35px;
  width: 10px;
  height: 10px;
  border-top: 1px solid #fff;
  border-right: 1px solid #fff;
  transform: rotate(45deg);
}
.l-header__list.u-flexWrap{
  position: static;
  flex-direction: row;
  padding: 20px 0;
  border-bottom: 1px solid #fff;
  justify-content: center;
}
.l-header__item:first-of-type{
  padding: 0 30px 0 0;
}
.l-header__item a{
  color: #fff;
}
.on {
  transform: translateX(0%);
  opacity: 1;
  pointer-events: auto;
}
.gnav-btn{
  width: 60px;
  height: 60px;
}
.icon-animation {
  display: block;
  z-index: 9998;
  position: absolute;
  top: 1rem;
  right: .3rem;
  width: 25px;
  height: 25px;
  float: right;
  text-align: center;
  cursor: pointer;
  display: block;

}
.icon-animation span {
  display: block;
  position: absolute;
  top: 10px;
  left: 43%;
  width: 25px;
  height: 3px;
  margin-left: -25px;
  transform: rotate(0deg);
  background: #000;
  transition: all 0.3s;
  display: block;
}
.icon-animation .top {
  transform: translateY(-5px);
  display: block;

}
.icon-animation .bottom {
  transform: translateY(13px);
  display: block;
}
.icon-animation .middle {
  transform: translateY(4px);
  display: block;
}
.is-open .middle {
  background: rgba(51, 51, 51, 0);
  display: block;
}
.is-open .top {
  transform: rotate(-45deg) translateY(0px);
  display: block;
}
.is-open .bottom {
  transform: rotate(45deg) translateY(0px);
  display: block;
}
.is-open .icon-animation span{
  top: 14px;
}

JavaScript例

function menuToggle() {
  var target = document.querySelector('.gnav-btn');
  var scrollWrap = document.querySelector('.l-wrapper');
  var body = document.body;
  var nav = document.querySelector('.l-nav');
    menuToggle.scrollTop = 0;

    target.addEventListener('click',onClick);

    function onClick(e) {      
      var scrollTop = window.scrollTop;

      if (target.classList.contains("is-open")) {
        target.classList.remove('is-open');
        nav.classList.remove('on');
        scrollWrap.style.cssText = ''; 
        body.style.cssText = '';
      } else {
        menuToggle.scrollTop = window.scrollY;
        body.style.overflow = 'hidden'
        scrollWrap.style.position = 'fixed';
        scrollWrap.style.width = '100%';
        scrollWrap.style.top = -menuToggle.scrollTop + 'px';
        target.classList.add('is-open');
        nav.classList.add('on');
      }
    }
}
menuToggle();

スクロール位置を検出して、positionで固める方法で実装してます。
この方法を知ったとき本当に目から鱗でした・・・

まとめ

今回も以前作成したjQueryVanilla.jsに置き換えてみました。
実はなかなか動かず苦しんでしまったので、ChatGPTに「どこかおかしいとこない?」と聞いたのは秘密です。

WEB制作担当ソーヤ

ソーヤ

上毛印刷WEB制作担当
前職は東証プライム企業の本社WEB受託チームにてフロントエンドエンジニアを3年経験。


この記事に対するご意見・ご感想・ご質問等ありましたら、
ぜひ下記フォームにてお送りください。

    お名前必須
    メールアドレス必須
    お問い合わせ内容必須
    PAGE TOP