上毛印刷株式会社

【JavaScript】ホバーしたら吹き出し風のメニューを表示する

【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で実装してみました。

コピペしてガンガン使ってください!

WEB制作担当ソーヤ

ソーヤ

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


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

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