jQueryで「マウスを重ねたときだけ見た目を変えたい」と思っても、hover()とmouseoverのどちらを使えばよいのか迷いますよね。
結論からいうと、現在はhover()を新しく使わず、on()でmouseenterとmouseleaveを設定します。ただし、色や枠線を変えるだけならCSSの:hoverで十分です。
この記事では、基本の書き方から、子要素へカーソルを移動したときの違い、スマートフォン・キーボード対応、補足表示の実例、動かないときの確認方法まで順番に解説します。
jQueryのhover処理はmouseenterとmouseleaveで書く
hover処理では、要素の内側へマウスが入ったときと、外側へ離れたときに別々のイベントが発生します。まずは次の流れを押さえておきましょう。

on()はイベントと実行する処理を結び付けるjQueryのメソッドです。次のコードでは、対象へ入ったときにクラスを追加し、離れたときに取り除きます。
$('.product-card')
.on('mouseenter', function () {
$(this).addClass('is-hovered');
})
.on('mouseleave', function () {
$(this).removeClass('is-hovered');
});thisはイベントが発生した要素を指します。カードが複数あっても、マウスを重ねたカードだけへis-hoveredクラスを付けられます。
hover()は非推奨になっている
以前は、次のhover()がよく使われていました。しかし、このメソッドはjQuery 3.3で非推奨になっています。既存コードを保守するとき以外は使わないようにしましょう。
// 新しく書くコードでは使用しません
$('.product-card').hover(
function () {
$(this).addClass('is-hovered');
},
function () {
$(this).removeClass('is-hovered');
}
);on('mouseenter', 処理)とon('mouseleave', 処理)へ分けると、ほかのイベントも同じ書き方で追加でき、処理の内容も追いやすくなります。
見た目だけを変えるならCSSの:hoverを使う
背景色、文字色、枠線など、見た目だけの変化にjQueryは必要ありません。CSSの:hoverを使うほうがコードが短く、JavaScriptを読み込めない場合にも装飾を適用できます。
.product-card:hover,
.product-card:focus-visible {
border-color: #2f66d0;
box-shadow: 0 18px 42px rgb(47 102 208 / 18%);
}:focus-visibleも一緒に指定すると、Tabキーでカードを選んだ人にも反応が伝わります。表示の変更に加えて、文章の差し替えや別の処理を実行したい場合にjQueryを使いましょう。
カードへhover処理を付ける実例
ここからは、カードへマウスを重ねると枠線と影が変わり、案内文も切り替わる例を作ります。最初の状態は次のとおりです。

HTMLでカードを作る
HTMLはindex.htmlへ記述します。カード全体をリンクにし、変更する案内文へproduct-card__hintクラスを付けます。
<a class="product-card" href="#details">
<div class="product-card__visual" aria-hidden="true">UI</div>
<div>
<h2>Webデザイン入門</h2>
<p>余白・配色・文字組みの基本を学びます。</p>
<span class="product-card__hint">
カーソルを合わせるか、Tabキーで選択してください
</span>
</div>
</a>
<script src="jquery-4.0.0.min.js"></script>
<script src="script.js"></script>jQuery本体を先に読み込み、そのあとに自分のscript.jsを読み込みます。順番が逆になると$ is not definedエラーになり、処理が動きません。
CSSで通常時と変化後の見た目を用意する
style.cssでは通常のカードと、is-hoveredクラスが付いた状態を分けて指定します。
.product-card {
display: grid;
grid-template-columns: 180px 1fr;
gap: 28px;
align-items: center;
padding: 28px;
border: 2px solid #dce4f1;
border-radius: 22px;
color: #172033;
background: #fff;
text-decoration: none;
transition: border-color .2s, box-shadow .2s;
}
.product-card.is-hovered {
border-color: #2f66d0;
box-shadow: 0 18px 42px rgb(47 102 208 / 18%);
}
.product-card:focus-visible {
outline: 4px solid #f5bd42;
outline-offset: 4px;
}
.product-card__visual {
width: 180px;
aspect-ratio: 1;
display: grid;
place-items: center;
border-radius: 24px;
color: #fff;
background: linear-gradient(135deg, #2f66d0, #7c5ce0);
font-size: 52px;
font-weight: 800;
}
.product-card__hint {
display: inline-block;
margin-top: 18px;
color: #2f66d0;
font-weight: 700;
}
@media (max-width: 640px) {
.product-card {
grid-template-columns: 1fr;
}
.product-card__visual {
width: 120px;
}
}
@media (prefers-reduced-motion: reduce) {
.product-card {
transition: none;
}
}変化後の装飾をクラスへまとめておくと、JavaScriptから個々のCSSプロパティを変更せずに済みます。デザインを直す場所もstyle.cssへ集約できます。
mouseenterとmouseleaveでクラスと文章を切り替える
続いてscript.jsへイベントを設定します。マウス操作だけでなく、Tabキーで選択したときにも同じ変化が起きるよう、focusinとfocusoutを追加します。
const $productCard = $('.product-card');
$productCard
.on('mouseenter focusin', function () {
$(this).addClass('is-hovered');
$(this).find('.product-card__hint').text('詳しい内容を表示中です');
})
.on('mouseleave focusout', function () {
$(this).removeClass('is-hovered');
$(this)
.find('.product-card__hint')
.text('カーソルを合わせるか、Tabキーで選択してください');
});イベント名を半角スペースで区切ると、同じ処理を複数のイベントへ設定できます。find()はカード内の案内文だけを探し、text()で文章を変更しています。

マウスをカードの外へ移動するとmouseleaveが発生し、クラスと案内文が元へ戻ります。ブラウザで何度か出入りし、変化が残らないことも確認してください。
mouseenterとmouseoverの違い
mouseenterとmouseoverは、どちらもマウスが要素へ入ったときに発生します。違いは、対象の中にある子要素へ移動したときの動作です。
| イベント | 子要素へ移動したとき | 向いている用途 |
|---|---|---|
mouseenter | 親要素へ入った1回として扱いやすい | カード、メニュー、ボタン全体のhover処理 |
mouseover | 子要素でも発生し、親へ伝わる | 子要素ごとの通過も検知したい処理 |
mouseleave | 対象全体から離れたときに発生する | mouseenterで付けた状態を戻す処理 |
mouseout | 子要素へ移動した場合にも発生する | 細かな移動を追跡する特殊な処理 |
カード内には見出し、画像、文章など複数の子要素があります。単純なhover表現なら、子要素を移動するたびに処理が繰り返されないmouseenterとmouseleaveの組み合わせが分かりやすいです。
hoverだけに頼らない補足表示を作る
マウスを重ねると補足が開くUIは便利ですが、タッチ操作には「カーソルを重ねる」という操作がありません。キーボード利用者も同じ情報を確認できるよう、フォーカスとクリックでも開けるようにします。

ボタンと補足をHTMLで関連付ける
<div class="help-area">
<button
id="help-button"
type="button"
aria-expanded="false"
aria-controls="help-popover"
>
用語の補足を見る
</button>
<aside id="help-popover" class="help-popover" hidden>
<h2>イベントとは?</h2>
<p>クリックやマウス移動など、ブラウザ上で起きる変化をイベントと呼びます。</p>
<a href="#more">さらに詳しく確認する</a>
</aside>
</div>aria-controlsで操作する補足のIDを示し、aria-expandedで開閉状態を伝えます。hidden属性がある間は、補足が画面にも支援技術にも表示されません。
マウス・フォーカス・クリックの処理を追加する
const $helpArea = $('.help-area');
const $helpButton = $('#help-button');
const $helpPopover = $('#help-popover');
function openHelp() {
$helpPopover.prop('hidden', false);
$helpButton.attr('aria-expanded', 'true');
}
function closeHelp() {
$helpPopover.prop('hidden', true);
$helpButton.attr('aria-expanded', 'false');
}
$helpArea
.on('mouseenter', openHelp)
.on('mouseleave', closeHelp)
.on('focusin', openHelp)
.on('focusout', function (event) {
if (!this.contains(event.relatedTarget)) {
closeHelp();
}
});
$helpButton.on('click', function () {
if ($helpPopover.prop('hidden')) {
openHelp();
} else {
closeHelp();
}
});
$(document).on('keydown', function (event) {
if (event.key === 'Escape' && !$helpPopover.prop('hidden')) {
$helpButton.trigger('focus');
closeHelp();
}
});focusoutでは、次にフォーカスされる要素をevent.relatedTargetで確認しています。補足内のリンクへ移動しただけなら閉じず、UI全体から離れたときだけ閉じます。
hoverで表示する内容は、マウスを補足の上へ移動しても消えず、Escキーなどで閉じられ、フォーカス中も確認できる状態が大切です。説明文や重要な操作をhoverでしか見られない設計にはしないでください。
あとから追加された要素へhover処理を設定する
Ajaxなどであとから追加されるカードには、ページ読み込み時の$('.product-card').on(...)ではイベントが付きません。この場合は、最初から存在する親要素へイベントを設定します。
$('.card-list')
.on('mouseenter', '.product-card', function () {
$(this).addClass('is-hovered');
})
.on('mouseleave', '.product-card', function () {
$(this).removeClass('is-hovered');
});この書き方をイベントの委譲と呼びます。対象が増えても親要素側でイベントを受け取れるため、カードを追加するたびに設定し直す必要がありません。
jQueryのhover処理が動かないときの確認項目
jQueryを先に読み込めているか
開発者ツールに$ is not definedと表示される場合は、jQuery本体が読み込まれていないか、script.jsより後ろにあります。読み込み順とファイルのパスを確認してください。
セレクタとHTMLのクラス名が一致しているか
$('.product-card')は、class="product-card"の要素を探します。ピリオドの付け忘れ、大文字・小文字、ハイフンの違いがないか見直しましょう。
mouseleaveの処理を忘れていないか
mouseenterでクラスを追加しただけでは、マウスが離れても見た目は戻りません。対になるmouseleaveでremoveClass()を実行します。
mouseoverで処理が何度も実行されていないか
カード内の画像や文章へ移動するたびに処理が繰り返されるなら、mouseoverではなくmouseenterを試してください。対応する終了イベントもmouseoutからmouseleaveへ変更します。
スマートフォンだけで確認していないか
タッチ画面ではhoverが発生しない、またはタップ後に状態が残る場合があります。実機ではタップによる本来の操作を確認し、hoverでしか実行できない機能を作らないことが重要です。
よくある質問
hoverで画像を切り替えられますか?
切り替えられます。ただし装飾用の画像ならCSSで背景画像や透明度を変える方法を先に検討してください。内容を持つ画像を切り替える場合は、代替テキストやタッチ操作でも情報を確認できるかを確認します。
hover中だけアニメーションを付けてもよいですか?
短い色や影の変化なら問題ありません。大きな移動や繰り返し動く表現は避け、prefers-reduced-motionで動きを減らしたい設定にも対応すると安心です。
CSSとjQueryのhoverを一緒に使えますか?
使えます。単純な見た目はCSS、文章の変更や状態管理はjQueryと役割を分けると管理しやすくなります。同じプロパティを両方から変更すると原因を追いにくいため、担当を重ねないようにしましょう。
まとめ
hover()は非推奨のため、on()でmouseenterとmouseleaveを設定する- 色や枠線など見た目だけの変更はCSSの
:hoverを使う - クラスを追加・削除し、デザインはCSSへまとめる
- カード全体の処理には、子要素で繰り返されにくい
mouseenterが扱いやすい - タッチとキーボードでも同じ情報や機能を利用できるようにする
まずは基本例をそのまま動かし、マウスを入れたとき、離したとき、Tabキーで選んだときの3つを確認してみてください。動作を分けて確認すると、hover処理でどこにつまずいているかも見つけやすくなります。
