ホバー時のみ表示させたい要素が、意図せず再表示になる問題。pointer-event: none;で解消されます。

ヘッダーナビをホバーした時に、子メニューが表示されるようにしたけど動き変。
マウスアウトして非表示にした後、要素があった箇所にマウスを移動させるとまた表示される!
なんで??opacity: 0;visibility: hidden;にしているのに……。

しんぺー

ホバー時に表示させる子メニューですが、transitionが入っていると完全に非表示になっておらず、意図せずマウスホバーして要素が再表示されることがあります。
子リストはデフォルトでpointer-event: none;、ホバー時だけpointer-event: auto;にすることで解消されます。

そもそもどういう問題?

問題のサンプルをCodePenで用意しました。
ホバーすると子要素が表示されます。一度マウスアウトしてから、子要素があった箇所にマウスを戻すと子要素が表示されてしまいます。

  • マウスホバーすると、子要素が表示
  • マウスアウトすると、子要素は非表示
  • 子要素があった箇所にマウスを戻すと、また子要素が表示される。

【原因】transitionの影響で、要素が完全に非表示になっていないことで起きます

See the Pen 極端な例 by shimpei (@shimpei) on CodePen.

しんぺー

子要素にtransitionを入れている場合に起きる問題です。
transition0にすると起きないですが、ふわっと表示・非表示させたいですよね。
解決方法を解説していきますね。

完成形のイメージ

最終的な完成形です。
マウスアウトした後に、子リストの箇所にマウスホバーしても子リストは表示されません。
いい感じですね。

See the Pen header nav hover by shimpei (@shimpei) on CodePen.

CodePenのサンプルは、大好きなchocolatさんカラーにしてみました。

解決方法

原因はtransitionでした。transitionで設定した時間内は要素は表示されています(見かけは透明でも)。
要素が完全に消えていない状態だと要素をホバーできるので、意図せず要素が表示されてしまいました。

これを解消するには、pointer-event: none;にして要素をホバーできなくすれば良いです。

CSS

  • 子リストはデフォルトで、pointer-event: none;
  • 親リストをホバーした時だけ、子リストをpointer-event: auto;にする
// 親のリスト
ul.h-navlist01 {
  > li {
    position: relative;
    &:hover {
      // 親リストをホバーしたら、子リストを表示
      ul.h-navlist01-child {
        // ホバーした時だけポインターイベント有効
        pointer-events: auto;

        opacity: 1;
        visibility: visible;
      }
    }
  }
}

// 子のリスト
ul.h-navlist01-child {
  // ポインターイベント無効(デフォルト)
  pointer-events: none;

  position: absolute;
  opacity: 0;
  visibility: hidden;
}

その他|実装時に役立つ小技

親リストと、子リストに隙間があるときは、子リストにmargin-topを入れます。

本題と別ですが実装時に役立つ小技を紹介します。
親リストと、子リストの間に隙間があるとマウスホバーが外れてしまいます。
マウスホバーが外れると、子リストは表示されません。そういった場合は隙間分だけ子リストにmargin-topを入れます。

margin-topでマウスホバーが外れる隙間を埋めます。

まとめ|子リストのポインターイベントを無効にする。

  • 子リストのポインターイベントは、デフォルトで無効にする(pointer-event: none;
  • 親リストをホバーしたときだけ、子リストのポインターイベントを有効にする(pointer-events: auto;

最後までありがとうございました!