CSSのpointer-eventsプロパティで特定要素のホバー・マウスオーバーイベントを無効化する方法
CSSのpointer-eventsプロパティを活用すれば、特定のHTML要素でマウスオーバー(:hover)イベントを無視・無効化できます。本記事では、実際のWeb制作で遭遇したホバー問題を例に、その解決方法を段階的に解説します。
最近、クライアント向けにチーム紹介ギャラリーページを制作しました。各ギャラリーアイテムはUIカードで表現されており、カードの上にマウスを乗せるとオーバーレイの色が変化する仕組みです。しかし開発中に予期しない問題に直面し、それがこのチュートリアルを書くきっかけとなりました。
UIカードの内容と構造
各ギャラリーカードは、次の要素で構成されています。
- 従業員の写真(白黒)
- 従業員名(白文字)
- 従業員の役職(白文字)
- 控えめな暗色の背景オーバーレイ
ユーザーがカードの上にマウスを乗せると、背景オーバーレイが明るい半透明の黄色(ブランドカラー)へと滑らかにトランジションします。
UIカードの実例
本チュートリアルでは問題の解決に焦点を絞るため、UIカードをデザイン面で簡略化したバージョンを用意しました。カードの上にマウスを乗せて、背景色が明るい黄色へ変化することを確認してみてください。
しかし、ここに問題があります。もうお気づきの方もいるかもしれません。テキスト部分の上にマウスを移動してみてください。何が起こるでしょうか?
マウスがテキスト要素の上に移動した瞬間、ホバーイベントがキャンセルされ、黄色から即座にデフォルトの非アクティブ状態(グレー)へ戻ってしまいます。これは許容できません。
以下がHTMLコードです。
<div class="card">
<div class="card-overlay"></div>
<img
class="card-image"
src="https://jp.wsxdn.com/UploadFiles_5590/202203/2022033109324298.jpg"
/>
<div class="card-info">
<div class="card-name">Employee Name</div>
<div class="card-role">Employee Role</div>
</div>
</div>
続いてCSSです。
.card {
max-width: 350px;
position: relative;
}
.card-overlay {
background-image: linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.5));
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
transition: background-color 0.6s;
}
.card-overlay:hover {
background-color: rgba(255, 204, 7, 0.5);
}
.card-image {
max-width: 100%;
display: block;
}
.card-info {
position: absolute;
bottom: 2rem;
left: 2rem;
}
.card-name,
.card-role {
color: white;
font-size: 1.5rem;
line-height: 1.25;
padding: 0.25rem;
}
.card-name {
font-weight: bold;
}
では、なぜテキスト部分にマウスを乗せるとホバーイベントがキャンセルされるのでしょうか?
原因はHTMLのスタッキング順序(重なり順)にあります。スタッキング順序は通常、CSSのz-indexプロパティで制御されます。しかし、CSSで明示的に指定しない場合、デフォルトのスタッキング順序が適用されるのです。
z-indexは重なり順を制御するCSSプロパティです。positionの値が同じ要素同士では、z-indexの値(数値)が最も大きい要素が他の要素より前面に配置されます。Webページ上のすべての要素のデフォルトのz-index値はautoで、これは0と同じ扱いになります。
今回のケースでは、2つの要素がどちらも絶対配置(absolute)で、どちらもデフォルトのz-index: auto(0)です。この場合、どちらが前面に来るのでしょうか(どちらかが勝たなければなりません)。
答えは、HTML内で後に記述された要素が勝ちます。
今回の場合、名前と役職のテキスト要素を含む<div class="card-info">コンテナが、card-overlay要素の後に記述されています。
<div class="card">
<div class="card-overlay"></div>
<img
class="card-image"
src="https://jp.wsxdn.com/UploadFiles_5590/202203/2022033109324298.jpg"
/>
<div class="card-info">
<div class="card-name">Employee Name</div>
<div class="card-role">Employee Role</div>
</div>
</div>
つまりUIカードの例では、マウスがテキスト要素の上に移動した時点で、オーバーレイ要素ではなくcard-info要素をホバーすることになります。しかし、:hover(疑似クラス)が設定されているのは.card-overlayだけです(前述のCSSコードを参照)。
では、どうすればよいのでしょうか?
対処法①:HTMLの記述順を入れ替える
<div class="card-overlay"></div>要素を物理的に<div class="card-info">...</div>要素の後ろへ移動させてみましょう。
<div class="card">
<img
class="card-image"
src="https://jp.wsxdn.com/UploadFiles_5590/202203/2022033109324298.jpg"
/>
<div class="card-info">
<div class="card-name">Employee Name</div>
<div class="card-role">Employee Role</div>
</div>
<div class="card-overlay"></div>
</div>
するとスタッキング順序が入れ替わり、次のようになります。
これでテキスト部分の上にマウスを乗せても、オーバーレイのトランジションが中断されなくなりました(実際に試してみてください)。
しかし、待ってください。今度はスタッキング順序が入れ替わったことで、オーバーレイがテキスト要素の前面に配置され、テキストがオーバーレイによってグレーがかってしまいました。
一つの問題を解決したと思ったら、別の問題を生み出してしまったのです。
この手法は使わないことにして、<div class="card-overlay">要素を元の位置へ戻しましょう。
対処法②:z-indexを指定する
では、.card-overlayクラスにz-index: 1を指定したらどうなるでしょうか?
これでcard-overlayは、デフォルトのz-index: 0のままのcard-infoよりも高い重なり順を持つため、前面に配置されます。ホバー時の色変化も再び中断されずに機能するようになります。しかし……
残念ながら、この方法の結果は、先ほどHTMLの記述順を入れ替えた場合とまったく同じです。今回はCSSで直接スタッキング順序を変更しただけで、テキスト要素は依然としてオーバーレイによってグレーがかったままです。
これではやはり許容できません!
pointer-eventsで問題を解決!
そこでふと思い出したのが、CSSには要素がポインターイベントに反応するかどうかを制御できるpointer-eventsというプロパティが存在するということです。
ポインターイベントとは、クリック、スクロール、要素の上へのマウス移動(ホバー)など、マウスに関わるすべての操作を指します。
そこで、.card-infoクラスにpointer-events: none;を追加しました。
.card-info {
position: absolute;
bottom: 2rem;
left: 2rem;
pointer-events: none; /* これが解決策! */
}
これで、テキスト部分を含むUIカード全体をホバーしても、ホバーイベントがキャンセルされなくなりました。さらに、テキスト要素は100%の白色を保ったまま表示されます。
コード全体はCodePenでも確認できます。
-
CSSでcontenteditable要素の境界線(枠線)を削除する方法
HTMLのcontenteditable属性を指定した要素は、ブラウザ上で直接テキストを編集できます。しかし、要素をクリックして編集モードにすると、多くのブラウザではデフォルトで青い枠線(アウトライン)が自動的に表示されます。この境界線を非表示にしたい場合は、CSSのoutlineプロパティを使用します。[contenteditable]セレクターに対してoutline: 0px solid transparent;を指定することで、編集時の枠線をきれいに取り除くことができます。コード例<!DOCTYPE html> <html> <head> <st
-
CSSでホバー時にトランジション(アニメーション)を追加する方法を解説
CSSでホバー時にトランジション(滑らかなアニメーション効果)を追加するには、transitionプロパティと:hover疑似クラスを組み合わせて使用します。あらかじめ要素にtransitionを設定しておくことで、ホバー時の変化が瞬時に切り替わるのではなく、指定した時間をかけてスムーズに変化するようになります。 サンプルコード <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1&q