ブートストラップドロップダウンにスライド効果を追加する


80

ブートストラップを使用していますが、ドロップダウンにアニメーションを追加したいと思います。それにアニメーションを追加し、それを離れるときに下にスライドして元に戻したいです。どうすればこれを行うことができますか?

私が試したこと:

次のようにJsドロップダウンファイルを変更します。

Bootstrapのナビゲーションドロップダウンをスムーズに上下にスライドさせるにはどうすればよいですか?


1
どこかにbootstrap-dropdown.jsを含めましたか?私はそれをヘッダーに見ません..そしてこれらのケーキをawwww。私は今とてもお腹が空いています!
ablm 2012

うーん、boostrap.jsの中にあります。含めましたが、機能しなかったので削除しましたが、再度追加しました。ミニのものを削除すると、まったく機能しません
Ben Beri 2012

編集:そうそう、それは含まれています。
ablm 2012

うーん。デフォルトのドロップダウンはスライドしません。(リンクからの)変更されたバージョンには、$ el.parent()。slideToggle();があります。これはJQueryアニメーションを呼び出します。
ablm 2012

そしてところで、なぜあなたがブートストラップを2回含めるのかわかりません。bootstrap.min.jsは縮小版です。
ablm 2012

回答:


149

Bootstrap 3(BS3)に更新すると、必要な機能を結び付けるのに適したJavascriptイベントが多数公開されます。BS3では、このコードはすべてのドロップダウンメニューにあなたが探しているアニメーション効果を与えます:

  // Add slideDown animation to Bootstrap dropdown when expanding.
  $('.dropdown').on('show.bs.dropdown', function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideDown();
  });

  // Add slideUp animation to Bootstrap dropdown when collapsing.
  $('.dropdown').on('hide.bs.dropdown', function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideUp();
  });

BS3イベントについてはこちら、具体的にはドロップダウンイベントについてはこちらをご覧ください


4
これのslideUp部分に問題があります。折りたたみモード(Chrome)では、ドロップダウンの幅は全画面で表示されているかのように幅に戻ります。FFを使用している間は下にスライドしますが、上にスライドする代わりに非表示になります。
ScubaSteve 2014

3
私もこの問題を見て、実際にそれについて具体的に尋ねる別のスレッドを作成しました... stackoverflow.com/questions/26267207/…しかし、私はそれを修正する方法を正確に知りません。ドロップダウンクラスは、hidden.bs.dropdownイベントを処理する前に遷移が完了するのを待っていないように感じます。
カイルジョンソン

3
これは機能し、私が望むことを実行しますが、モバイルビューポートでは、サブメニューのドロップダウンスライドアップが速く消えて途切れ途切れに見えます-共有に感謝します!
イロおじさん2016年

これを機能させることができません。次のエラーが発生し続けます:「UncaughtTypeError:$(...)。find(...)。first(...)。stop is notfunction」。イベントが発生したときにアニメーションがまだ開始されていない限り、.stop()が関数ではないことを理解していませんか?何が足りないのですか?
ジョン

モバイルの修正については、さらに下のSlipochの回答を参照してください。
tashows 2018

71

また、この小さなコードをスタイルに追加することで、ドロップダウン効果にJavaScriptを使用することを避け、CSS3トランジションを使用することもできます。

.dropdown .dropdown-menu {
    -webkit-transition: all 0.3s;
    -moz-transition: all 0.3s;
    -ms-transition: all 0.3s;
    -o-transition: all 0.3s;
    transition: all 0.3s;

    max-height: 0;
    display: block;
    overflow: hidden;
    opacity: 0;
}

.dropdown.open .dropdown-menu { /* For Bootstrap 4, use .dropdown.show instead of .dropdown.open */
    max-height: 300px;
    opacity: 1;
}

この方法の唯一の問題は、max-heightを手動で指定する必要があることです。非常に大きな値を設定すると、アニメーションが非常に速くなります。

ドロップダウンのおおよその高さがわかっている場合は、チャームのように機能します。それ以外の場合でも、javascriptを使用して正確な最大高さの値を設定できます。

ここに小さな例があります:DEMO


!このソリューションにはパディングに関する小さなバグがあります。JacobStammのコメントとソリューションを確認してください。


2
素晴らしい解決策、感謝します。
ラリトナラヤンミシュラ2016

私はこれが大好きですが、残念ながら、スライドダウンアニメーションは1回しか機能しません。メニューを閉じて、ページを更新せずにもう一度開くと、すぐに開きます。この問題を抱えている人は他にいますか?
ネイサンR

8
素晴らしいソリューション。残念ながら、小さなバグがあります。ドロップダウンの最初のアイテムは、折りたたまれている場合でもクリックできます。折りたたまれたドロップダウンの少し下にカーソルを合わせるとわかります。この場合、最初のオプションはプレーンテキストであるため、大したことではありません。ただし、リンクの場合は問題です。私の解決策は、可視性も「アニメーション化」することですが、他のものがアニメーション化を終了した後、実行を遅らせます。チェックしてください:jsfiddle.net/stamminator/kjLe1tfs/1
Jacob Stamm

そのバグを指摘してくれてありがとう、ジェイコブ。これはリストのパディングに問題があるようです。よろしければ、私はあなたの解決策を追加して答えます。
MadisonTrash 2016年

1
pointer-events:none折りたたまれたバージョンに追加point-events: allして、メニューに追加することもできます.show
Gray Ayer

24

私はそのようなことをしていますが、クリックではなくホバーで..これは私が使用しているコードです。クリックで動作するように少し調整できるかもしれません

$('.navbar .dropdown').hover(function() {
  $(this).find('.dropdown-menu').first().stop(true, true).delay(250).slideDown();
}, function() {
  $(this).find('.dropdown-menu').first().stop(true, true).delay(100).slideUp()
});

これはうまくいきます!しかし、クリックする代わりにマウスホバーでそれを操作する方法はありますか?
arefin2k

上に投稿したコードは、クリックではなくマウスホバーにあります。
ヨーン

いいね!ありがとう。
ilmk

私のために働いていません。私は下にこれを追加<script>のタグが、何も起こらなかった
YaddyVirus

16

このスレッドをぶつけることができるかどうかはわかりませんが、開いているクラスの削除が速すぎると発生する視覚的なバグの簡単な修正を見つけました。基本的には、slideUpイベント内にOnComplete関数を追加し、すべてのアクティブなクラスと属性をリセットするだけです。このようになります:

結果は次のとおりです。Bootplyの例

Javascript / Jquery:

$(function(){
    // ADD SLIDEDOWN ANIMATION TO DROPDOWN //
    $('.dropdown').on('show.bs.dropdown', function(e){
        $(this).find('.dropdown-menu').first().stop(true, true).slideDown();
    });

    // ADD SLIDEUP ANIMATION TO DROPDOWN //
    $('.dropdown').on('hide.bs.dropdown', function(e){
        e.preventDefault();
        $(this).find('.dropdown-menu').first().stop(true, true).slideUp(400, function(){
            //On Complete, we reset all active dropdown classes and attributes
            //This fixes the visual bug associated with the open class being removed too fast
            $('.dropdown').removeClass('show');
            $('.dropdown-menu').removeClass('show');
            $('.dropdown').find('.dropdown-toggle').attr('aria-expanded','false');
        });
    });
});

デモでは、数回続けてクリックすると、1つのメニューが開いたままになります。
SventoryMang 2016年

@DOTangええ、それは完璧ではなかったと思います。したがって、迅速な修正です。少しリファクタリングすると改善されると思います。うまくいけば、Bootstrap4がリリースされるまでに、彼らはそれを修正するでしょう
IndieRok 2016年

11

スライド&フェード効果の解決策は次のとおりです。

   // Add slideup & fadein animation to dropdown
   $('.dropdown').on('show.bs.dropdown', function(e){
      var $dropdown = $(this).find('.dropdown-menu');
      var orig_margin_top = parseInt($dropdown.css('margin-top'));
      $dropdown.css({'margin-top': (orig_margin_top + 10) + 'px', opacity: 0}).animate({'margin-top': orig_margin_top + 'px', opacity: 1}, 300, function(){
         $(this).css({'margin-top':''});
      });
   });
   // Add slidedown & fadeout animation to dropdown
   $('.dropdown').on('hide.bs.dropdown', function(e){
      var $dropdown = $(this).find('.dropdown-menu');
      var orig_margin_top = parseInt($dropdown.css('margin-top'));
      $dropdown.css({'margin-top': orig_margin_top + 'px', opacity: 1, display: 'block'}).animate({'margin-top': (orig_margin_top + 10) + 'px', opacity: 0}, 300, function(){
         $(this).css({'margin-top':'', display:''});
      });
   });

ありがとう。コードは完全に機能します。しかし、なぜ$(this).css({'margin-top':''});@Vedmantが必要なのかよくわかりません
DucCuong

これは、アニメーションの完了後にmargin-topパラメーターを削除するためです。ドロップダウンにカスタムスタイルでマージンが追加されている場合(私のテーマのように)、orig_margin_top backにアニメーション化するため、それなしで動作する必要がありますが、余分なものを残さない方がクリーンですアニメーションが完了した後のインラインスタイル。
Vedmant 2015年

9

2018ブートストラップ4を更新

Boostrap 4では、.openクラスはに置き換えられました.show。追加のJSやjQueryを必要とせずに、CSSトランジションのみを使用してこれを実装したかったのです...

.show > .dropdown-menu {
  max-height: 900px;
  visibility: visible;
}

.dropdown-menu {
  display: block;
  max-height: 0;
  visibility: hidden;
  transition: all 0.5s ease-in-out;
  overflow: hidden;
}

デモ:https//www.codeply.com/go/3i8LzYVfMF

注:max-heightドロップダウンコンテンツに対応するのに十分な任意の大きな値に設定できます。


これは完全に機能します。私にとっては、を使用して別の効果を達成しようとしていたので、最大の高さを指定する必要さえありませんでしたmargin-top
Supreme Dolphin

私はこれが好きです、
..– aswzen

8

クリックすると、以下のコードを使用して実行できます

$('.dropdown-toggle').click(function() {
  $(this).next('.dropdown-menu').slideToggle(500);
});

これはうまく機能しますが、フォーカスを失うと、ドロップダウンは開いたままになりますが、これは正常ではありません。
バリーマイケルドイル

7

上記のコードを使用していますが、slideToggleによって遅延効果を変更しました。

アニメーションでホバー時にドロップダウンをスライドします。

$('.navbar .dropdown').hover(function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideToggle(400);
    }, function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideToggle(400)
    });

1
実際に2回定義する必要はありません。トグルを使用すると、秒がなくても機能します。
ダラス

3

拡張された答えは、私の最初の答えだったので、以前に十分な詳細がなかった場合は言い訳になります。

Bootstrap 3.xの場合、私は個人的にCSSアニメーションを好み、animate.cssとBootstrapドロップダウンJavascriptフックを使用しています。かなり柔軟なアプローチを採用した後は、正確な効果が得られない可能性があります。

ステップ1: headタグを使用してanimate.cssをページに追加します。

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.4.0/animate.min.css">

ステップ2:トリガーで標準のブートストラップHTMLを使用します。

<div class="dropdown">
  <button type="button" data-toggle="dropdown">Dropdown trigger</button>

  <ul class="dropdown-menu">
    ...
  </ul>
</div>

ステップ3:次に、2つのカスタムデータ属性をdropdrop-menu要素に追加します。inアニメーションの場合はdata-dropdown-in、outアニメーションの場合はdata-dropdown-out。これらは、fadeInやfadeOutなどのanimate.cssエフェクトにすることができます。

<ul class="dropdown-menu" data-dropdown-in="fadeIn" data-dropdown-out="fadeOut">
......
</ul>

ステップ4:次に、次のJavascriptを追加して、data-dropdown-in / outデータ属性を読み取り、Bootstrap Javascript APIフック/イベント(http://getbootstrap.com/javascript/#dropdowns-events)に反応します。

var dropdownSelectors = $('.dropdown, .dropup');

// Custom function to read dropdown data
// =========================
function dropdownEffectData(target) {
  // @todo - page level global?
  var effectInDefault = null,
      effectOutDefault = null;
  var dropdown = $(target),
      dropdownMenu = $('.dropdown-menu', target);
  var parentUl = dropdown.parents('ul.nav'); 

  // If parent is ul.nav allow global effect settings
  if (parentUl.size() > 0) {
    effectInDefault = parentUl.data('dropdown-in') || null;
    effectOutDefault = parentUl.data('dropdown-out') || null;
  }

  return {
    target:       target,
    dropdown:     dropdown,
    dropdownMenu: dropdownMenu,
    effectIn:     dropdownMenu.data('dropdown-in') || effectInDefault,
    effectOut:    dropdownMenu.data('dropdown-out') || effectOutDefault,  
  };
}

// Custom function to start effect (in or out)
// =========================
function dropdownEffectStart(data, effectToStart) {
  if (effectToStart) {
    data.dropdown.addClass('dropdown-animating');
    data.dropdownMenu.addClass('animated');
    data.dropdownMenu.addClass(effectToStart);    
  }
}

// Custom function to read when animation is over
// =========================
function dropdownEffectEnd(data, callbackFunc) {
  var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
  data.dropdown.one(animationEnd, function() {
    data.dropdown.removeClass('dropdown-animating');
    data.dropdownMenu.removeClass('animated');
    data.dropdownMenu.removeClass(data.effectIn);
    data.dropdownMenu.removeClass(data.effectOut);

    // Custom callback option, used to remove open class in out effect
    if(typeof callbackFunc == 'function'){
      callbackFunc();
    }
  });
}

// Bootstrap API hooks
// =========================
dropdownSelectors.on({
  "show.bs.dropdown": function () {
    // On show, start in effect
    var dropdown = dropdownEffectData(this);
    dropdownEffectStart(dropdown, dropdown.effectIn);
  },
  "shown.bs.dropdown": function () {
    // On shown, remove in effect once complete
    var dropdown = dropdownEffectData(this);
    if (dropdown.effectIn && dropdown.effectOut) {
      dropdownEffectEnd(dropdown, function() {}); 
    }
  },  
  "hide.bs.dropdown":  function(e) {
    // On hide, start out effect
    var dropdown = dropdownEffectData(this);
    if (dropdown.effectOut) {
      e.preventDefault();   
      dropdownEffectStart(dropdown, dropdown.effectOut);   
      dropdownEffectEnd(dropdown, function() {
        dropdown.dropdown.removeClass('open');
      }); 
    }    
  }, 
});

ステップ5(オプション):アニメーションを高速化または変更する場合は、次のようにCSSを使用して行うことができます。

.dropdown-menu.animated {
  /* Speed up animations */
  -webkit-animation-duration: 0.55s;
  animation-duration: 0.55s;
  -webkit-animation-timing-function: ease;
  animation-timing-function: ease;
}

興味のある人がいれば、より詳細な記事を書き、ダウンロードしてください:記事:http://bootbites.com/tutorials/bootstrap-dropdown-effects-animatecss

それがお役に立てば幸いです。この2回目の記事には、トムに必要な詳細レベルが含まれています。


3
あなたの答えに少なくともいくつかの詳細を含めるのは良いことです-あなたのサイトにリンクするだけでは本当に良い答えではありません。
ajshort 2016年

@GeraldSchneiderは、回答をより詳細に更新しました。stackoverflowに関する私の最初の答えだったので、フィードバックに感謝します。
トムジェームス

2
$('.navbar .dropdown').hover(function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideDown();
}, function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideUp();
});

このコードは、ホバー時にドロップダウンを表示する場合に機能します。

私は変更.slideToggle.slideDown.slideUp、および削除(400)のタイミングを


1

これは、jQueryうまく機能するを使用した簡単な解決策です。

$('.dropdown-toggle').click(function () {
    $(this).next('.dropdown-menu').slideToggle(300);
});

$('.dropdown-toggle').focusout(function () {
    $(this).next('.dropdown-menu').slideUp(300);
})

スライドアニメーションの切り替えはクリックすると発生し、フォーカスを失うと常に上にスライドします。

300値を任意の値に変更します。数値が小さいほど、アニメーションが速くなります。

編集:

このソリューションは、デスクトップビューでのみ機能します。モバイルでうまく表示するには、さらに変更が必要です。


これは私にとってはうまくいきますが、マウスをサブメニューに移動すると(つまり、から離れるとdropdown-toggle)、再び消えます。つまり、サブメニュー項目を選択できません
Bassie 2017年

1

BOOTSTRAP3リファレンス

私はこのスレッドの解決策にとらわれ続け、それは毎回私を詰め込むので追加されました。

基本的に、BSドロップダウンはすぐに削除します .open親からクラスをため、上にスライドしても機能しません。

slideDown();の他のソリューションと同じビットを使用します。

// ADD SLIDEUP ANIMATION TO DROPDOWN //
$('.dropdown').on('hide.bs.dropdown', function(e){
  e.preventDefault();
  $(this).find('.dropdown-menu').first().stop(true, true).slideUp(300, function(){
    $(this).parent().removeClass('open');
  });
});

0

Bootstrap 3の場合、上記の回答のこのバリエーションにより、モバイルslideUp()アニメーションがスムーズになります。Bootstrapは.openトグルの親からクラスをすぐに削除するため、上記の回答はアニメーションが途切れます。このコードは、slideUp()アニメーションが終了するまでクラスを復元​​します。

// Add animations to topnav dropdowns
// based on https://stackoverflow.com/a/19339162
// and https://stackoverflow.com/a/52231970

$('.dropdown')
  .on('show.bs.dropdown', function() {
    $(this).find('.dropdown-menu').first().stop(true, true).slideDown(300);
  })
  .on('hide.bs.dropdown', function() {
    $(this).find('.dropdown-menu').first().stop(true, false).slideUp(300, function() {
      $(this).parent().removeClass('open');
    });
  })
  .on('hidden.bs.dropdown', function() {
    $(this).addClass('open');
  });

主な違い:

  • ではhide.bs.dropdown、イベントハンドラ私が使用しています.stop()(のデフォルト値をfalse(2番目の引数のために)jumpToEnd
  • hidden.bs.dropdownイベントハンドラは、復元し.open、ドロップダウントグルの親にクラスを、そしてそれはかなりすぐにクラスが最初に除去された後にこれを行います。その間、slideUp()アニメーションはまだ実行されており、上記の回答と同様に、「the-animation-is-completed」コールバックが最終的に削除されます。.openクラスを親から。
  • 各イベントハンドラーのセレクターが同じであるため、メソッドはチェーン化されます

0

イントロ

執筆時点で、元の回答は8歳になりました。それでも、元の質問に対する適切な解決策はまだないように感じます。

それ以来、ブートストラップは大きく進歩し、現在は4.5.2になっています。ます。この回答は、まさにこのバージョンに対応しています。

これまでの他のすべての解決策の問題

他のすべての回答の問題は、show.bs.dropdown/にフックしている間hide.bs.dropdown、フォローアップイベントshown.bs.dropdown/hidden.bs.dropdownが早すぎる(アニメーションがまだ進行中)か、抑制されているためにまったく起動しない(e.preventDefault())ということです。

クリーンなソリューション

Bootstrapsクラスのshow()との実装にはいくつかの類似点があるため、元の動作を模倣するときにそれらをグループ化し、QoLヘルパー関数をとに少し追加しました。Bootstrapと同じ方法で/イベントを作成します。このイベントは、アニメーションが完了した後に発生します-予想どおりです。hide()DropdowntoggleDropdownWithAnimation()showDropdownWithAnimation()hideDropdownWithAnimation()
toggleDropdownWithAnimation()shown.bs.dropdownhidden.bs.dropdown

/**
 * Toggle visibility of a dropdown with slideDown / slideUp animation.
 * @param {JQuery} $containerElement The outer dropdown container. This is the element with the .dropdown class.
 * @param {boolean} show Show (true) or hide (false) the dropdown menu.
 * @param {number} duration Duration of the animation in milliseconds
 */
function toggleDropdownWithAnimation($containerElement, show, duration = 300): void {
    // get the element that triggered the initial event
    const $toggleElement = $containerElement.find('.dropdown-toggle');
    // get the associated menu
    const $dropdownMenu = $containerElement.find('.dropdown-menu');
    // build jquery event for when the element has been completely shown
    const eventArgs = {relatedTarget: $toggleElement};
    const eventType = show ? 'shown' : 'hidden';
    const eventName = `${eventType}.bs.dropdown`;
    const jQueryEvent = $.Event(eventName, eventArgs);

    if (show) {
        // mimic bootstraps element manipulation
        $containerElement.addClass('show');
        $dropdownMenu.addClass('show');
        $toggleElement.attr('aria-expanded', 'true');
        // put focus on initial trigger element
        $toggleElement.trigger('focus');
        // start intended animation
        $dropdownMenu
            .stop() // stop any ongoing animation
            .hide() // hide element to fix initial state of element for slide down animation
            .slideDown(duration, () => {
            // fire 'shown' event
            $($toggleElement).trigger(jQueryEvent);
        });
    }
    else {
        // mimic bootstraps element manipulation
        $containerElement.removeClass('show');
        $dropdownMenu.removeClass('show');
        $toggleElement.attr('aria-expanded', 'false');
        // start intended animation
        $dropdownMenu
            .stop() // stop any ongoing animation
            .show() // show element to fix initial state of element for slide up animation
            .slideUp(duration, () => {

            // fire 'hidden' event
            $($toggleElement).trigger(jQueryEvent);
        });
    }
}

/**
 * Show a dropdown with slideDown animation.
 * @param {JQuery} $containerElement The outer dropdown container. This is the element with the .dropdown class.
 * @param {number} duration Duration of the animation in milliseconds
 */
function showDropdownWithAnimation($containerElement, duration = 300) {
    toggleDropdownWithAnimation($containerElement, true, duration);
}

/**
 * Hide a dropdown with a slideUp animation.
 * @param {JQuery} $containerElement The outer dropdown container. This is the element with the .dropdown class.
 * @param {number} duration Duration of the animation in milliseconds
 */
function hideDropdownWithAnimation($containerElement, duration = 300) {
    toggleDropdownWithAnimation($containerElement, false, duration);
}

イベントリスナーをバインドする

アニメーションでドロップダウンを表示/非表示にするための適切なコールバックを作成したので、実際にこれらを正しいイベントにバインドしましょう。

他の回答でよく見られる間違いは、イベントリスナーを要素に直接バインドすることです。これは、イベントリスナーの登録時に存在するDOM要素に対しては正常に機能しますが、後で追加される要素にはバインドされません。

そのため、一般的にdocument:に直接バインドする方が良いでしょう。

$(function () {

    /* Hook into the show event of a bootstrap dropdown */
    $(document).on('show.bs.dropdown', '.dropdown', function (e) {
        // prevent bootstrap from executing their event listener
        e.preventDefault();
        
        showDropdownWithAnimation($(this));
    });

    /* Hook into the hide event of a bootstrap dropdown */
    $(document).on('hide.bs.dropdown', '.dropdown', function (e) {
        // prevent bootstrap from executing their event listener
        e.preventDefault();
          
        hideDropdownWithAnimation($(this));
    });

});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.