브라우저에서 CSS3 전환 기능을 어떻게 정규화합니까?


91

Webkit의 전환 종료 이벤트는 webkitTransitionEnd, Firefox는 transitionEnd, Opera는 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
}

어떤 목적으로 거짓입니까?
통화 나

답변:


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
oTransitionEnd는 Opera에서 otransitionend로 소문자로 변경되었습니다. 참조 opera.com/docs/specs/presto2.10/#m274
vieron

1
이제는 모두 소문자로 된 transitionend입니다. 참조는 dev.w3.org/csswg/css3-transitions/#transition-events
gossi

1
MsTransition 비트를 제거했지만 나머지 답변은 그대로 둡니다. 모든 주요 비 WebKit 브라우저의 현재 버전에는 공급 업체 접두사가 필요하지 않습니다. transition그리고 transitionend충분하다. 참조 : caniuse.com/#search=transitions
webinista 2013 년

4
재정의가 필요한 이유 undefined 입니까?
Atav32

1
@ Atav32, 저도 궁금합니다. 내가 생각할 수있는 유일한 것은 다른 누군가가 이미 그것을 재정의 할 경우를 대비해 거기에 있다는 것입니다.
Qtax

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')
});

라이브러리가없는 자바 스크립트에서는 약간 장황합니다.

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

function callfunction() {
   //do whatever
}

마지막에서 두 번째로 낙타가 아니어야합니다.
wwaawaw

7
재미있게도 저는 여기에 왔습니다. 제 동료
들이이

1
@Duopixel은 Chrome과 Safari에서 두 가지 이벤트를 발생 시키므로 답변을 테스트하고 변경하는 것을 고려해보십시오 (최소한 다른 모든 Webkit 브라우저와 이전 Firefox 및 Opera). msTransitionend여기에는 필요하지 않습니다.
Dan

1
둘 이상의 속성이 전환 된 경우 여러 이벤트를 트리거합니다. 참조 : stackoverflow.com/a/18689069/740836
Nick Budden 2015

8

최신 정보

다음은이를 수행하는 더 깨끗한 방법이며 모 더니 저가 필요하지 않습니다.

$(".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없이 작성할 수 있습니까?
alt

2
jQuery 버전은 적어도 Webkit 기반 브라우저에서 두 개의 이벤트를 발생시킵니다.
Dan

2
@Dan 대신 하나를 사용하므로 한 번만 실행됩니다
Tom

죄송합니다 . one대신이 ( 가)있는 것을 알아 차리지 못했습니다 on. 너무 뻔 했어!
Dan

8

jQuery 및 Bootstrap을 사용하는 경우 $.support.transition.end 하면 현재 브라우저에 맞는 이벤트를 반환합니다.

그것은되는 부트 스트랩에 정의 와에 사용되는 자사의 애니메이션 콜백 JQuery와 문서는 이러한 속성에 의존하지 말 불구하고 :

이러한 속성 중 일부는 아래에 설명되어 있지만 긴 지원 중단 / 제거주기가 적용되지 않으며 내부 jQuery 코드에서 더 이상 필요하지 않으면 제거 될 수 있습니다.

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


2
여기에서 가장 간단한 솔루션이기 때문에 이러한 경고가있는 것은 정말 아쉽습니다.
Ninjakannon 2013-08-13

1
여기에 코드에 추가되었습니다. github.com/twbs/bootstrap/blob/…
Tom

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
살만 폰 압바스을

이 답변이 지금도 적용됩니까? (2016 년 1 월)
Jessica

그냥 IE 11에서 테스트 그것은 거짓 반환
제시카

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

Google 클로저를 사용하면이 작업을 수행 할 필요가 없습니다. 요소가있는 경우 :

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를 지정하여 항목을 추가 할 수 있으며 브라우저에 도달하지 않으면 표준을 사용합니다. 이벤트를 사용하면 다음과 같이 쉽게 바인딩 할 수 있습니다.

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

감사! 나는 비슷한 일을했지만 브라우저가 스니핑하지 않았습니다. 결과 (및 코드)는 cssglue.com/cubic 에서 볼 수 있습니다 . 솔루션의 유일한 문제는 브라우저 공급 업체가 전환 이벤트를 표준화하기로 결정하면 접두사를 삭제하고 작동을 멈출 수 있다는 것입니다 (아직 가능성이 낮음). 그러나 예, 코드를 훨씬 더 깔끔하게 만듭니다.
methodofaction 2011 년

나는 내 것을 더 나은 것으로 대체하려고했지만 다른 한편으로는 그것의 단순함을 좋아한다.
Rich Bradshaw 2011

2
그만한 가치가 있습니다. 이것은 브라우저 스니핑없이 수행 할 수 있습니다object.bind('transitionend oTransitionEnd webkitTransitionEnd', function() { // callback } );
Matijs 2011

1
접두사가 transitionend없는 이벤트 버전의 이름 은이 아니라으로 지정 TransitionEnd됩니다.
mgol

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.