【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で固める方法で実装してます。
この方法を知ったとき本当に目から鱗でした・・・
まとめ
今回も以前作成したjQueryをVanilla.jsに置き換えてみました。
実はなかなか動かず苦しんでしまったので、ChatGPTに「どこかおかしいとこない?」と聞いたのは秘密です。
この記事に対するご意見・ご感想・ご質問等ありましたら、
ぜひ下記フォームにてお送りください。