【jQuery】アニメーション後に要素を削除する完全ガイド|fadeOut・slideUp・複数削除・確認UI・CSS比較まで

要素を削除するとき、remove() だけでは瞬時に消えてUXが悪くなります。jQueryのアニメーションコールバックを活用することで、フェードアウト・スライドアップ後に要素をDOMから取り除く滑らかな削除が実現できます。

この記事でわかること

  • コールバックでremove()を呼ぶ基本パターン(fadeOut・slideUp・animate)
  • promise()/then()を使ったPromise形式の書き方
  • 複数要素を順番にアニメーションして削除する方法
  • 削除後に「リストが空です」メッセージを表示する方法
  • 削除確認ダイアログとの組み合わせ
  • 親要素ごとアニメーション削除する(closest()活用)
  • CSSトランジション+クラス付与で削除する方法との比較
スポンサーリンク

コールバックでremove()を呼ぶ基本パターン

アニメーションメソッドの最後の引数に関数を渡すと、アニメーション完了後にその関数が実行されます。このコールバック内でremove()を呼ぶのが最もシンプルな実装です。

fadeOut()で消えてから削除

// フェードアウト後に削除
$('#notification').fadeOut(400, function () {
  $(this).remove();
});

slideUp()でたたんでから削除

// スライドアップ後に削除
$('#alert-msg').slideUp(300, function () {
  $(this).remove();
});

animate()で任意のアニメーション後に削除

// 右にスライドしながら透明になって削除
$('#item').animate(
  { opacity: 0, marginLeft: '100px' },
  350,
  function () {
    $(this).remove();
  }
);
コールバック内のthisは対象要素のDOMオブジェクト
コールバック内の this はアニメーションを実行した要素のネイティブDOMオブジェクトです。jQueryメソッドを使う場合は $(this).remove() のように $() で包んでください。アニメーション全般の詳細はアニメーション完全ガイドを参照してください。

promise()/then()を使ったPromise形式

jQueryの promise() メソッドを使うと、アニメーション完了を待つ処理をPromise形式で書けます。複数のアニメーションを連鎖させる場合にコードが読みやすくなります。

// promise().then()で書く
$('#notification').fadeOut(400).promise().then(function () {
  $('#notification').remove();
});

// 複数のアニメーションを連鎖
$('#card')
  .animate({ opacity: 0.5 }, 200)
  .slideUp(300)
  .promise()
  .then(function () {
    $('#card').remove();
    console.log('削除完了');
  });

// jQuery 3.x以降: async/awaitとの組み合わせ
async function removeWithAnimation(selector) {
  await $(selector).fadeOut(400).promise();
  $(selector).remove();
}
promise()はアニメーションキューが空になると解決する
$(el).fadeOut(400).promise() はfadeOutが完了した時点でresolveされます。then() にはjQuery Deferredオブジェクトが渡されるため、jQuery 3.0以降ではネイティブのPromise/async-awaitとも連携できます。

複数要素を順番にアニメーションして削除する

リストの全項目を順番に消去するなど、複数要素を1つずつアニメーションするパターンです。

each()で個別に遅延を付けて削除

// リスト項目を順番にフェードアウトして削除
$('#my-list li').each(function (i) {
  $(this).delay(i * 100).fadeOut(300, function () {
    $(this).remove();
  });
});

再帰関数で1つずつ順番に削除(前が消えてから次へ)

function removeNext($items, index) {
  if (index >= $items.length) return;  // 全て削除したら終了

  $($items[index]).slideUp(200, function () {
    $(this).remove();
    removeNext($items, index + 1);  // 次の要素へ
  });
}

$('#delete-all').on('click', function () {
  var $items = $('#my-list li');
  removeNext($items, 0);
});
delay()とコールバック再帰の使い分け

  • delay()で遅延: 全要素が同時にアニメーション開始(タイミングだけずれる)。シンプルで高速
  • 再帰関数: 前の要素が消えてから次が開始。厳密な順番が必要な場合に使う

削除後に「リストが空です」メッセージを表示する

ToDo リストや通知一覧で、全件削除後に空の状態を適切に表示するパターンです。

<ul id="todo-list">
  <li>タスク1 <button class="del-btn">削除</button></li>
  <li>タスク2 <button class="del-btn">削除</button></li>
  <li>タスク3 <button class="del-btn">削除</button></li>
</ul>
<p id="empty-msg" style="display:none; color:#999;">タスクはありません。</p>
$(function () {
  function checkEmpty() {
    if ($('#todo-list li').length === 0) {
      $('#empty-msg').fadeIn(300);
    }
  }

  $(document).on('click', '.del-btn', function () {
    $(this).closest('li').slideUp(250, function () {
      $(this).remove();
      checkEmpty();  // 削除後に空チェック
    });
  });
});
コールバック内でlengthをチェックするタイミング
DOMからremove()した直後に li の個数を数えているため、削除した要素は既にDOMに存在しません。アニメーション開始前に数えると、まだDOMにある状態でカウントしてしまい「空」と判定されないので注意してください。

削除確認ダイアログとの組み合わせ

誤操作を防ぐために確認ダイアログを挟んでからアニメーション削除するパターンです。confirm() と、カスタムダイアログの2種類を紹介します。

confirm()を使うシンプルな実装

$(document).on('click', '.del-btn', function () {
  var $item = $(this).closest('li');
  var name  = $item.find('.item-name').text();

  if (!confirm('「' + name + '」を削除しますか?')) {
    return;  // キャンセルなら何もしない
  }

  $item.slideUp(250, function () {
    $(this).remove();
  });
});

インライン確認UI(ボタンを「本当に削除」に変える)

$(document).on('click', '.del-btn', function () {
  var $btn  = $(this);
  var $item = $btn.closest('li');

  if (!$btn.hasClass('is-confirming')) {
    // 1回目クリック: 確認状態に変える
    $btn.addClass('is-confirming').text('本当に削除する');

    // 3秒後に元に戻す
    setTimeout(function () {
      $btn.removeClass('is-confirming').text('削除');
    }, 3000);

  } else {
    // 2回目クリック(確認状態): 実際に削除
    $item.fadeOut(300, function () {
      $(this).remove();
    });
  }
});

親要素ごとアニメーション削除する(closest()活用)

削除ボタンが子要素にある場合、closest() で親要素を取得してまとめてアニメーション削除するパターンです。カード型UIでよく使われます。

<div class="card-list">
  <div class="card">
    <h3 class="card-title">記事タイトル1</h3>
    <button class="card-del">✕ 削除</button>
  </div>
  <div class="card">
    <h3 class="card-title">記事タイトル2</h3>
    <button class="card-del">✕ 削除</button>
  </div>
</div>
$(function () {
  $(document).on('click', '.card-del', function () {
    var $card = $(this).closest('.card');  // 削除ボタンの親カードを取得

    $card.animate(
      { opacity: 0, height: 0, marginBottom: 0, paddingTop: 0, paddingBottom: 0 },
      350,
      function () {
        $(this).remove();
      }
    );
  });
});
heightとmargin/paddingも同時アニメーション
カード要素を削除する際に height: 0 だけでなく marginBottom: 0 paddingTop: 0 paddingBottom: 0 もアニメーションすることで、後続のカードが自然な位置に詰まる滑らかな動きになります。

CSSトランジション+クラス付与で削除する(jQueryなし対応)

CSSのtransitionを使うと、jQueryの animate() よりGPU処理でパフォーマンスが良い場合があります。jQueryはクラスの付与とDOM削除のタイミング管理のみ担当します。

.list-item {
  opacity: 1;
  max-height: 200px;
  overflow: hidden;
  transition: opacity 0.3s ease, max-height 0.3s ease, margin 0.3s ease;
}

.list-item.is-removing {
  opacity: 0;
  max-height: 0;
  margin-bottom: 0;
}
$(document).on('click', '.del-btn', function () {
  var $item = $(this).closest('.list-item');

  $item.addClass('is-removing');  // CSSトランジション開始

  // トランジション完了後(300ms)にremove()
  setTimeout(function () {
    $item.remove();
  }, 300);

  // transitionendイベントで正確に検知する方法
  // $item[0].addEventListener('transitionend', function handler() {
  //   $item.remove();
  //   $item[0].removeEventListener('transitionend', handler);
  // });
});
setTimeout vs transitionendイベント

  • setTimeout(fn, 300): シンプルで確実。CSSのtransition-durationと値を合わせる必要あり
  • transitionendイベント: 実際のトランジション完了を検知するため厳密。ただしイベントが複数発火することがあるため一度だけ呼ぶ処理が必要

削除アニメーション方法の比較と選び方

方法 コード量 パフォーマンス タイミング精度 向いている用途
fadeOut(fn)/slideUp(fn) 少ない 普通 ◎(コールバック) 通知・アラート・単純な削除
animate(fn) 中程度 普通 カスタムアニメーション(スライド・縮小)
promise().then() 中程度 普通 削除後に連鎖処理が必要な場合
CSSトランジション+クラス 多め(CSS必要) 高い(GPU) ○(setTimeout) 大量要素・モバイル重視

まとめ

jQueryのアニメーション後に要素を削除するには、コールバックで remove() を呼ぶ方法が最もシンプルで確実です。複数削除・空状態表示・確認ダイアログなどの実務的なパターンを組み合わせて活用してください。

関連記事: アニメーション完全ガイド(animate・fadeIn/Out・slideToggle) / 要素を削除する方法 / slideToggle()がカクつく原因と対処法

よくある質問(FAQ)

QfadeOut()後にremove()しなくても要素は消えませんか?
AfadeOut() はアニメーション完了後に display:none を設定しますが、DOMからは削除されません。要素はHTML上に残り続けるためメモリを占有し、$("li").length でもカウントされます。不要な要素はアニメーション後に remove() でDOMから完全に削除してください。
Qアニメーション中に削除ボタンを連打されると挙動がおかしくなります。
Aボタンクリック直後に $(this).prop("disabled", true) でボタンを無効化するか、if ($item.is(":animated")) return; でアニメーション中は処理をスキップしてください。また stop(true) で前のアニメーションをキャンセルしてから再実行する方法もあります。
Qdetach()とremove()の違いは何ですか?
Aremove() は要素とそれに紐付いたイベントハンドラー・データを全て削除します。detach() はDOMから取り外しますが、イベントハンドラーとデータは保持します。「一時的に非表示にして後で再挿入する」場合は detach() を使い、完全に不要な要素には remove() を使ってください。
QslideUp()で高さがアニメーションされず一瞬で消えます。
A要素に display:none が既に設定されているか、height:0 などのCSSが干渉している可能性があります。また、要素が position:absolute の場合もslideUpが効かないことがあります。slideToggle()がカクつく原因と対処法も参照してください。
Q動的に追加した要素の削除ボタンがクリックされません。
AAjax等で動的に追加した要素は $(selector).on("click", fn) ではイベントが登録されません。親要素や document に委譲イベントを登録してください:$(document).on("click", ".del-btn", fn)。動的要素のイベント登録についての詳細はtrigger()メソッド完全ガイドも参考になります。