ブラウザ間でCSS3トランジション機能を正規化するにはどうすればよいですか?


91

Webkitの移行終了イベントはwebkitTransitionEndと呼ばれ、FirefoxはtransitionEnd、オペラはoTransitionEndです。純粋なJSでそれらすべてに取り組む良い方法は何ですか?ブラウザをスニッフィングする必要がありますか?またはそれぞれを個別に実装しますか?私には思いつかなかった他の方法がありますか?

つまり:

//doing browser sniffing
var transitionend = (isSafari) ? "webkitTransitionEnd" : (isFirefox) ? "transitionEnd" : (isOpera) ? "oTransitionEnd";

element.addEventListener(transitionend, function(){
  //do whatever
},false);

または

// Assigning an event listener per browser
element.addEventListener("webkitTransitionEnd", fn);
element.addEventListener("oTransitionEnd", fn);
element.addEventListener("transitionEnd", fn);

function fn() {
   //do whatever
}

どんな目的のために偽ですか?
call-me

回答:


166

Modernizrで使用されているテクニックが改善されています。

function transitionEndEventName () {
    var i,
        undefined,
        el = document.createElement('div'),
        transitions = {
            'transition':'transitionend',
            'OTransition':'otransitionend',  // oTransitionEnd in very old Opera
            'MozTransition':'transitionend',
            'WebkitTransition':'webkitTransitionEnd'
        };

    for (i in transitions) {
        if (transitions.hasOwnProperty(i) && el.style[i] !== undefined) {
            return transitions[i];
        }
    }

    //TODO: throw 'TransitionEnd event is not supported in this browser'; 
}

次に、遷移終了イベントが必要なときにいつでもこの関数を呼び出すことができます。

var transitionEnd = transitionEndEventName();
element.addEventListener(transitionEnd, theFunctionToInvoke, false);

3
OperaではoTransitionEndがotransitionendに小文字になりました。opera.com/docs/specs/presto2.10/#m274を
vieron 2012

1
また、現在はすべて小文字で遷移します。参照してくださいdev.w3.org/csswg/css3-transitions/#transition-events
gossi

1
MsTransitionビットを削除しましたが、残りの回答はそのまま残します。すべての主要な非WebKitブラウザーの現在のバージョンでは、ベンダープレフィックスは必要ありません。transitionそしてtransitionend十分です 参照:caniuse.com/#search=transitions
webinista

4
なぜそれを再定義する必要があるのundefinedですか?
Atav32 14

1
@ Atav32、私もそうだろう。私が考えることができる唯一のことは、誰かがそれをすでに何かに再定義した場合にそこにあるということです。
Qtax 2015年

22

Matijsコメントによると、遷移イベントを検出する最も簡単な方法は、ライブラリ(この場合はjquery)を使用することです。

$("div").bind("webkitTransitionEnd.done oTransitionEnd.done otransitionend.done transitionend.done msTransitionEnd.done", function(){
  // Unlisten called events by namespace,
  // to prevent multiple event calls. (See comment)
  // By the way, .done can be anything you like ;)
  $(this).off('.done')
});

ライブラリなしのJavaScriptでは、少し冗長になります。

element.addEventListener('webkitTransitionEnd', callfunction, false);
element.addEventListener('oTransitionEnd', callfunction, false);
element.addEventListener('transitionend', callfunction, false);
element.addEventListener('msTransitionEnd', callfunction, false);

function callfunction() {
   //do whatever
}

最後から2番目のものはcamelCasedであってはなりません。
wwaawaw

7
おかしなことに、私がここに来たのは、私の同僚がこの回答とまったく同じように見える複数のイベントがコードにスローされたことを発見したためです
2013年

1
@Duopixelは回答をテストして変更を検討してください。ChromeとSafariで2つのイベントがスローされます(少なくとも他のすべてのWebkitブラウザと古いFirefoxとOpera)。msTransitionendここでは必要ありません。
Dan

1
複数のプロパティを移行すると、複数のイベントがトリガーされます。参照:stackoverflow.com/a/18689069/740836
Nick Budden、

8

更新

以下はそれを行うよりクリーンな方法であり、modernizrを必要としません

$(".myClass").one('transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd', 
function() {
 //do something
});

あるいは

var transEndEventNames = {
        'WebkitTransition': 'webkitTransitionEnd',
        'MozTransition': 'transitionend',
        'OTransition': 'oTransitionEnd otransitionend',
        'msTransition': 'MSTransitionEnd',
        'transition': 'transitionend'
    }, transitionEnd = transEndEventNames[Modernizr.prefixed('transition')];

これは、Modernizrによって提案されたコードに基づいていますが、Operaの新しいバージョンには追加のイベントがあります。

http://modernizr.com/docs/#prefixed


1
これはすばらしい方法ですが、Modernizrが必要です。これは単純に記述できますが、Modernizrはありませんか?
2012

2
jQueryバージョンは(少なくとも)Webkitベースのブラウザで2つのイベントを発生させます。
Dan

2
@Danは代わりに1つ使用するため、1度だけ起動します
Tom

申し訳ありませんが、のone代わりにあなたがいることに気付きませんでしたon。それはとても明白でした!
Dan

8

jQueryを使用すると、Bootstrap $.support.transition.endは現在のブラウザーに適切なイベントを返します。

これはBootstrap定義され、アニメーションコールバックで使用されますが、jQueryドキュメントはこれらのプロパティに依存しないように言っています:

これらのプロパティの一部を以下に記載しますが、これらは長い非推奨/削除サイクルの対象ではなく、内部jQueryコードで不要になった場合は削除される可能性があります。

http://api.jquery.com/jQuery.support/


2
ここで最も簡単な解決策であるので、これはそのような警告があるのは本当に残念です。
Ninjakannon 2013

1
ここは自分のコードに追加されますgithub.com/twbs/bootstrap/blob/...
トム・

6

2015年の時点で、このワンライナーは取引を行う必要があります(IE 10 +、Chrome 1 +、Safari 3.2 +、FF 4+およびOpera 12 +):-

var transEndEventName = ('WebkitTransition' in document.documentElement.style) ? 'webkitTransitionEnd' : 'transitionend'

イベントリスナーのアタッチは簡単です:-

element.addEventListener(transEndEventName , theFunctionToInvoke);

素敵なソリューション。残念ながら、それはどうかを教えてくれませんtransitionend、すべてのサポートされていません。 var transEndEventName = ('WebkitTransition' in document.documentElement.style) ? 'webkitTransitionEnd' : ('transitionend' in document.documentElement.style) ? 'transitionend' : false; そして、簡単なチェックを実行します。 if(transEndEventName) element.addEventlistener(transEndEventName, theFunctionToInvoke)
Luuuud

私はそれを個別にチェックする必要があると思います:stackoverflow.com/a/29591030/362006
Salman von Abbas

この答えは今にも当てはまりますか?(2016年1月)
ジェシカ

IE 11でテストしたところ、falseが返されました
ジェシカ

1

2番目は行く方法です。すべてのブラウザーでこれらのイベントの1つだけが発生するので、すべてのイベントを設定できます。


1

これはよりクリーンな方法です

 function transitionEvent() {
      // Create a fake element
      var el = document.createElement("div");

      if(el.style.OTransition) return "oTransitionEnd";
      if(el.style.WebkitTransition) return "webkitTransitionEnd";
      return "transitionend";
    }

0

グーグル閉鎖は、これを行う必要がないことを確認します。要素がある場合:

goog.events.listen(element, goog.events.EventType.TRANSITIONEND, function(event) {
  // ... your code here
});

goog.events.eventtype.jsのソースを見て、TRANSITIONENDはuseragentを見て計算されます。

// CSS transition events. Based on the browser support described at:
  // https://developer.mozilla.org/en/css/css_transitions#Browser_compatibility
  TRANSITIONEND: goog.userAgent.WEBKIT ? 'webkitTransitionEnd' :
      (goog.userAgent.OPERA ? 'oTransitionEnd' : 'transitionend'),

0

このようなコードを使用します(jQueryを使用)

var vP = "";
var transitionEnd = "transitionend";
if ($.browser.webkit) {
    vP = "-webkit-";
    transitionEnd = "webkitTransitionEnd";
} else if ($.browser.msie) {
    vP = "-ms-";
} else if ($.browser.mozilla) {
    vP = "-moz-";
} else if ($.browser.opera) {
    vP = "-o-";
    transitionEnd = "otransitionend"; //oTransitionEnd for very old Opera
}

これにより、JSを使用して、プロパティに連結されたvPを指定することで、JavaScriptを追加できます。ブラウザーにヒットしなかった場合は、標準を使用します。イベントを使用すると、次のように簡単にバインドできます。

object.bind(transitionEnd,function(){
    callback();
});

ありがとう!私は同様のことをしましたが、ブラウザを盗聴しませんでした。結果(およびコード)は、cssglue.com / cubicで確認できます。ソリューションの唯一の問題は、ブラウザーベンダーが移行イベントを標準化することを決定した場合、プレフィックスが削除され、動作しなくなる可能性があることです(まだ可能性は低いですが)。しかし、はい、それはコードをよりきれいにします。
methodofaction 2011年

私は同意します、私は私のものをより良いものと交換するつもりでしたが、その一方で私はそれのシンプルさが好きです。
リッチブラッドショー、2011

2
それが価値があるもののために。これは、ブラウザスニッフィングなしで行うことができますobject.bind('transitionend oTransitionEnd webkitTransitionEnd', function() { // callback } );
Matijs

1
プレフィックスなしのイベントの名前はtransitionend、ではなくTransitionEndです。
mgol 2013年

0

jqueryオーバーライド:

(function ($) {
  var oldOn = $.fn.on;

  $.fn.on = function (types, selector, data, fn, /*INTERNAL*/ one) {
    if (types === 'transitionend') {
      types = 'transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd';
    }

    return oldOn.call(this, types, selector, data, fn, one);
  };
})(jQuery);

そして使用法のような:

$('myDiv').on('transitionend', function() { ... });

0

受け入れられた答えは正しいですが、もう一度その要素を再作成する必要はありません。

グローバル変数を作成し、関数を追加します。

(function(myLib, $, window, document, undefined){

/**
 * @summary
 * Returns the browser's supported animation end event type.
 * @desc
 * @see {@link https://jonsuh.com/blog/detect-the-end-of-css-animations-and-transitions-with-javascript/}
 * @function myLib.getAnimationEndType
 * @return {string} The animation end event type
 */
(function(){
   var type;

   myLib.getAnimationEndType = function(){
      if(!type)
         type = callback();
      return type;

      function callback(){
         var t,
             el = document.createElement("fakeelement");

         var animations = {
            "animation"      : "animationend",
            "OAnimation"     : "oAnimationEnd",
            "MozAnimation"   : "animationend",
            "WebkitAnimation": "webkitAnimationEnd"
         }

         for (t in animations){
            if (el.style[t] !== undefined){
               return animations[t];
            }
         }
      }
   }
}());

/**
 * @summary
 * Returns the browser's supported transition end event type.
 * @desc
 * @see {@link https://jonsuh.com/blog/detect-the-end-of-css-animations-and-transitions-with-javascript/}
 * @function myLib.getTransitionEndType
 * @return {string} The transition end event type
 */
(function(){
   var type;

   myLib.getTransitionEndType = function(){
      if(!type)
         type = callback();
      return type;

      function callback(){
         var t,
             el = document.createElement("fakeelement");

         var transitions = {
            "transition"      : "transitionend",
            "OTransition"     : "oTransitionEnd",
            "MozTransition"   : "transitionend",
            "WebkitTransition": "webkitTransitionEnd"
         }

         for (t in transitions){
            if (el.style[t] !== undefined){
               return transitions[t];
            }
         }
      }
   }
}());

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