この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:3
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: マウスアウトイベント(mouseout / mouseleave)
SEOタイトル: jQuery mouseout と mouseleave の違い・子要素バブリング問題と現代の代替

この記事の要点
  • mouseout は子要素に出入りするたびに発火(バブリング)
  • mouseleave本当に親要素の外に出たときだけ発火(実用的)
  • $(e).hover(in, out) = mouseenter + mouseleave のシンタックスシュガー
  • CSS の :hover で済むことは CSS でやる方が速い
  • タッチデバイス対応は touchend / pointerleave も考慮

mouseout と mouseleave の違い(最重要)

同じように見えて、子要素を含むときの動作が全く違います:

外側
内側

マウスを「外側 → 内側 → 外側 → 外」と動かすと:

動きmouseoutmouseleave
外側 → 内側★発火(外側から出た扱い)発火しない
内側 → 外側★発火(内側から出た)発火しない
外側 → 完全に外発火★発火(本当に出た)

結論: 「要素から出たら何かする」用途では mouseleave を使うべき。mouseout は子要素の数だけ無駄に発火します。

hover() で書く(推奨)

// hover(enterFn, leaveFn) は mouseenter + mouseleave
$('.menu').hover(
    function() { $(this).addClass('active'); },   // マウス入った
    function() { $(this).removeClass('active'); } // マウス出た
);

// 1 関数だけだと両方で呼ばれる
$('.menu').hover(function() {
    $(this).toggleClass('active');
});

// 同等の on() 記法
$('.menu')
    .on('mouseenter', function() { $(this).addClass('active'); })
    .on('mouseleave', function() { $(this).removeClass('active'); });

CSS :hover で済むなら CSS を使う

JS で処理する必要が無い見た目変化はCSS :hover が最速かつ最軽量:

/* ホバー時に背景色変更 */
.menu {
    background: #fff;
    transition: background 0.2s;
}
.menu:hover {
    background: #e3f2fd;
}

/* 子要素を表示 */
.dropdown:hover .menu {
    display: block;
}

/* タッチデバイスでは :hover が「タップ後 hover 状態」になる罠 */
@media (hover: hover) {
    .btn:hover { background: blue; }
}

イベントオブジェクトと relatedTarget

// どこから来た / どこに行ったか
$('#box').on('mouseout', function(e) {
    console.log('to:', e.relatedTarget);   // 出た後どこにいるか
});
$('#box').on('mouseover', function(e) {
    console.log('from:', e.relatedTarget); // 入る前どこにいたか
});

// 「mouseout だが子要素への移動は無視したい」場合
$('#box').on('mouseout', function(e) {
    if (this.contains(e.relatedTarget)) return;  // まだ box の中
    console.log('本当に出た');
});
// → mouseleave と同じ動作になる

動的に追加された要素にもバインドしたい

// ❌ 後から追加された .item には効かない
$('.item').on('mouseleave', handler);

// ✅ Event Delegation で親に登録
$('#list').on('mouseleave', '.item', handler);

// ただし mouseleave/mouseenter はバブリングしないため
// jQuery が内部で mouseout/mouseover に変換して動作させている
// イベント大量発火するのでパフォーマンス注意

タッチデバイス・Pen 対応: Pointer Events

// Pointer Events はマウス・タッチ・ペンを統合
$('#box')
    .on('pointerenter', () => console.log('hover 開始'))
    .on('pointerleave', () => console.log('hover 終了'));

// タッチで擬似 hover を作りたい場合
$('#item')
    .on('touchstart', function() { $(this).addClass('hover'); })
    .on('touchend touchcancel', function() {
        $(this).removeClass('hover');
    });

// CSS で実現する場合
// @media (hover: hover) { .btn:hover { ... } }
// → ポインタが hover 可能なときだけ :hover 適用

Vanilla JS で書き直す

const box = document.getElementById('box');

box.addEventListener('mouseleave', e => {
    console.log('離脱');
});

box.addEventListener('mouseenter', e => {
    console.log('進入');
});

// Event Delegation
document.getElementById('list').addEventListener('mouseover', e => {
    const item = e.target.closest('.item');
    if (!item) return;
    // mouseenter 相当の判定
    if (item.contains(e.relatedTarget)) return;
    console.log('item hover:', item);
});

// pointerleave (推奨: マウス+タッチ+ペン統合)
box.addEventListener('pointerleave', e => { ... });

使い分けまとめ

用途推奨
見た目の変化のみCSS :hover
要素を出たときに 1 回処理mouseleave
要素+子要素の出入りを全て検知mouseout
マウス・タッチ・ペン統合pointerleave
ホバー時の処理セットhover(in, out)

FAQ

Q: mouseleave が発火しないことがある
A: マウスがブラウザウィンドウ外に高速移動した場合、ブラウザ側で発火しないことあり。Mouse Leave Listener を window にも追加するなど対策。

Q: hover() は jQuery が非推奨にした?
A: 非推奨ではないが、mouseenter + mouseleave で書く方が明示的。新規コードは Vanilla JS の pointerenter/leave 推奨。

Q: タッチでも hover 効果を出したい
A: touchstart で class 追加、touchend / touchcancel で class 削除。または CSS の :active を使う手も。