9/7まで 最大30%OFF 初心者編|無料コーディング教材|HTML・CSS・jQueryを実践で学ぶ

jQueryのhover処理の書き方|mouseenter・mouseleaveとスマホ対応を初心者向けに解説

jQuery hoverの使い方を示すアイキャッチ

jQueryで「マウスを重ねたときだけ見た目を変えたい」と思っても、hover()mouseoverのどちらを使えばよいのか迷いますよね。

結論からいうと、現在はhover()を新しく使わず、on()mouseentermouseleaveを設定します。ただし、色や枠線を変えるだけならCSSの:hoverで十分です。

この記事では、基本の書き方から、子要素へカーソルを移動したときの違い、スマートフォン・キーボード対応、補足表示の実例、動かないときの確認方法まで順番に解説します。

jQueryのhover処理はmouseenterとmouseleaveで書く

hover処理では、要素の内側へマウスが入ったときと、外側へ離れたときに別々のイベントが発生します。まずは次の流れを押さえておきましょう。

mouseenterとmouseleaveで処理が切り替わる流れ
要素へマウスが入るとmouseenter、外へ離れるとmouseleaveが発生します。

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処理を付ける実例

ここからは、カードへマウスを重ねると枠線と影が変わり、案内文も切り替わる例を作ります。最初の状態は次のとおりです。

hover前のWebデザイン入門カード
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キーで選択したときにも同じ変化が起きるよう、focusinfocusoutを追加します。

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()で文章を変更しています。

mouseenterで枠線と影が変化したカード
mouseenterが発生するとクラスが付き、枠線・影・案内文が変化します。

マウスをカードの外へ移動するとmouseleaveが発生し、クラスと案内文が元へ戻ります。ブラウザで何度か出入りし、変化が残らないことも確認してください。

mouseenterとmouseoverの違い

mouseentermouseoverは、どちらもマウスが要素へ入ったときに発生します。違いは、対象の中にある子要素へ移動したときの動作です。

イベント子要素へ移動したとき向いている用途
mouseenter親要素へ入った1回として扱いやすいカード、メニュー、ボタン全体のhover処理
mouseover子要素でも発生し、親へ伝わる子要素ごとの通過も検知したい処理
mouseleave対象全体から離れたときに発生するmouseenterで付けた状態を戻す処理
mouseout子要素へ移動した場合にも発生する細かな移動を追跡する特殊な処理

カード内には見出し、画像、文章など複数の子要素があります。単純なhover表現なら、子要素を移動するたびに処理が繰り返されないmouseentermouseleaveの組み合わせが分かりやすいです。

hoverだけに頼らない補足表示を作る

マウスを重ねると補足が開くUIは便利ですが、タッチ操作には「カーソルを重ねる」という操作がありません。キーボード利用者も同じ情報を確認できるよう、フォーカスとクリックでも開けるようにします。

hover・フォーカス・クリックで補足を開いた画面
マウス、Tabキー、クリックのどれでも同じ補足を開き、Escキーでも閉じられる例です。

ボタンと補足を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でクラスを追加しただけでは、マウスが離れても見た目は戻りません。対になるmouseleaveremoveClass()を実行します。

mouseoverで処理が何度も実行されていないか

カード内の画像や文章へ移動するたびに処理が繰り返されるなら、mouseoverではなくmouseenterを試してください。対応する終了イベントもmouseoutからmouseleaveへ変更します。

スマートフォンだけで確認していないか

タッチ画面ではhoverが発生しない、またはタップ後に状態が残る場合があります。実機ではタップによる本来の操作を確認し、hoverでしか実行できない機能を作らないことが重要です。

よくある質問

hoverで画像を切り替えられますか?

切り替えられます。ただし装飾用の画像ならCSSで背景画像や透明度を変える方法を先に検討してください。内容を持つ画像を切り替える場合は、代替テキストやタッチ操作でも情報を確認できるかを確認します。

hover中だけアニメーションを付けてもよいですか?

短い色や影の変化なら問題ありません。大きな移動や繰り返し動く表現は避け、prefers-reduced-motionで動きを減らしたい設定にも対応すると安心です。

CSSとjQueryのhoverを一緒に使えますか?

使えます。単純な見た目はCSS、文章の変更や状態管理はjQueryと役割を分けると管理しやすくなります。同じプロパティを両方から変更すると原因を追いにくいため、担当を重ねないようにしましょう。

まとめ

  • hover()は非推奨のため、on()mouseentermouseleaveを設定する
  • 色や枠線など見た目だけの変更はCSSの:hoverを使う
  • クラスを追加・削除し、デザインはCSSへまとめる
  • カード全体の処理には、子要素で繰り返されにくいmouseenterが扱いやすい
  • タッチとキーボードでも同じ情報や機能を利用できるようにする

まずは基本例をそのまま動かし、マウスを入れたとき、離したとき、Tabキーで選んだときの3つを確認してみてください。動作を分けて確認すると、hover処理でどこにつまずいているかも見つけやすくなります。