【JavaScript】ホバーしたら吹き出し風のメニューを表示する
2024年01月31日
WEBサイト制作
- #HTML
- #css
- #JavaScript
- #tips
こんにちは!
上毛印刷WEB制作担当のソーヤです。
今回はグローバルナビゲーションやページ固有のメニューなどに使える非常に便利なギミックを紹介します。
実装例
HTML例
<ul class="speech-bubble">
<li class="js-hover">
<a href="javascript:void(0);">製品情報</a>
<div class="bubblemenu">
<div class="bubblemenu-content">
<div class="bubblemenu-inner">
<ul>
<li><a href="/blog/javascript-attach-the-global-navigation-to-the-top-of-the-screen-by-scrolling/">【JavaScript】スクロールでグローバルナビゲーションを画面上部に追従させる</a></li>
<li><a href="/blog/javascript-apple-music-like-text-flows-and-focuses-when-it-comes-to-the-center/">【JavaScript】Apple Music風にテキストが流れて、中央にきたらフォーカスする</a></li>
<li><a href="/blog/javascript-sliding-selection-icons-in-global-navigation/">【JavaScript】グローバルナビゲーションに滑るような選択アイコンを表示</a></li>
<li><a href="/blog/javascript-display-images-in-a-flowing-loop/">【JavaScript】画像を流れるようにループ表示する</a></li>
</ul>
</div>
</div>
</div>
</li>
<li class="js-hover">
<a href="javascript:void(0);">安全性情報</a>
<div class="bubblemenu">
<div class="bubblemenu-content">
<div class="bubblemenu-inner">
<ul>
<li><a href="/blog/play-armored-core-6-on-steam-deck/">Steam Deckでアーマード・コア6をプレイ!</a></li>
<li><a href="/blog/i-watched-aftersun-aftersun/">aftersun/アフターサンを観ました。</a></li>
<li><a href="/blog/i-watched-tar-tar/">TAR/ターを観ました。</a></li>
<li><a href="/blog/best-attraction-movie-i-watched-the-super-mario-brothers-movie/">最高のアトラクション映画!ザ・スーパーマリオブラザーズ・ムービーを観ました。</a></li>
</ul>
</div>
</div>
</div>
</li>
<li class="js-hover">
<a href="javascript:void(0);">セミナーのご案内</a>
<div class="bubblemenu">
<div class="bubblemenu-content">
<div class="bubblemenu-inner">
<ul>
<li><a href="/blog/what-are-the-effects-of-gimbals/">ジンバルによる効果とは?</a></li>
<li><a href="/blog/recommendation-video-recording-equipment/">オススメ!動画収録機材</a></li>
</ul>
</div>
</div>
</div>
</li>
</ul>
ここで重要なのが、js-hoverを<li>に設定していることです。
もし<a>に設定してしまうと、カーソルを動かした際にmouseleaveイベントが発火して、吹き出し箇所が消えてしまいます。
CSS例
.speech-bubble{
display: flex;
list-style: none;
}
.speech-bubble > li{
margin: 0 10px;
position: relative;
transition: .2s;
}
.speech-bubble > li:before{
opacity: 0;
box-sizing: border-box;
position: absolute;
bottom: -3px;
left: 50%;
transform: translateX(-50%) translateY(25px);
width: 9px;
height: 9px;
box-shadow: 3px 8px 19px -8px rgba(0,0,0,0.6);
border: 6px solid transparent;
border-bottom: 9px solid #000;
content: '';
transition: .2s;
}
.speech-bubble > li.is-arrow:before{
opacity: 1;
transform: translateX(-50%) translateY(15px);
}
.speech-bubble > li > a{
background-color: #313131;
padding: 10px;
border-radius: 10px;
transition: .4s;
display: block;
color: #fff;
text-decoration: none;
}
.speech-bubble a:hover{
opacity: .7;
}
.bubblemenu{
position: absolute;
top: 30px;
left: 0;
opacity: 0;
pointer-events: none;
transition: .2s;
transform: translateY(10px);
padding: 10px 0 0;
width: 100%;
}
.bubblemenu-content{
padding: 20px 0 0;
}
.bubblemenu-inner{
width: 375px;
box-shadow: 3px 8px 19px -8px rgba(0,0,0,0.6);
padding: 10px;
border-radius: 10px;
position: relative;
background-color: #fff;
}
.is-active{
opacity: 1;
pointer-events: auto;
transform: translateY(0);
}
.bubblemenu-content li{
margin: 0 0 10px;
}
.bubblemenu-content li:last-of-type{
margin: 0;
}
JavaScript例
document.addEventListener("DOMContentLoaded", function() {
var megamenuElements = document.querySelectorAll('.js-hover');
megamenuElements.forEach(function(element) {
element.addEventListener('mouseenter', function() {
element.querySelector('.bubblemenu').classList.add('is-active');
element.classList.add('is-arrow');
});
element.addEventListener('mouseleave', function() {
element.querySelector('.bubblemenu').classList.remove('is-active');
element.classList.remove('is-arrow');
});
});
});
まとめ
今回もjQueryではなく、Vanilla.jsで実装してみました。
コピペしてガンガン使ってください!
この記事に対するご意見・ご感想・ご質問等ありましたら、
ぜひ下記フォームにてお送りください。