Eventos de transição CSS3

Respostas:

210

Rascunho de Transições CSS do W3C

A conclusão de uma transição CSS gera um evento DOM correspondente. Um evento é disparado para cada propriedade que passa por uma transição. Isso permite que um desenvolvedor de conteúdo execute ações sincronizadas com a conclusão de uma transição.


Webkit

Para determinar quando uma transição é concluída, defina uma função de ouvinte de evento JavaScript para o evento DOM que é enviado no final de uma transição. O evento é uma instância do WebKitTransitionEvent e seu tipo é webkitTransitionEnd.

box.addEventListener( 'webkitTransitionEnd', 
    function( event ) { alert( "Finished transition!" ); }, false );

Mozilla

Há um único evento que é acionado quando as transições são concluídas. No Firefox, o evento é transitionendno Opera oTransitionEnde no WebKit webkitTransitionEnd.

Ópera

Existe um tipo de evento de transição disponível. O oTransitionEndevento ocorre na conclusão da transição.

Internet Explorer

O transitionendevento ocorre na conclusão da transição. Se a transição for removida antes da conclusão, o evento não será acionado.


Estouro de pilha: Como normalizo as funções de transição CSS3 nos navegadores?

Davor Lucic
fonte
3
Observe que o evento é chamado de "transição" no firefox e "oTransitionEnd" no Opera
Andreas Köberle
8
Ninguém mencionou nada sobre a parte inicial da pergunta. Não há como registrar um manipulador de eventos a ser disparado antes do início da transição?
Tyler
Existe agora uma maneira padrão de conseguir isso? Parece 2 anos é muito tempo! As coisas provavelmente mudaram.
Fuzz suave
@tyler Eu não sei como contornar a falta de transição de início.
Davor Lucic
A questão @ stackildflow ligada ao Soft Fuzz tem uma solução interessante.
Davor Lucic
73

Atualizar

Todos os navegadores modernos agora suportam o evento não corrigido:

element.addEventListener('transitionend', callback, false);

https://caniuse.com/#feat=css-transitions


Eu estava usando a abordagem dada por Pete, mas agora comecei a usar o seguinte

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

Como alternativa, se você usar o bootstrap, poderá simplesmente fazer

$(".myClass").one($.support.transition.end,
function() {
 //do something
});

Isso acontece porque eles incluem o seguinte em bootstrap.js

+function ($) {
  'use strict';

  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
  // ============================================================

  function transitionEnd() {
    var el = document.createElement('bootstrap')

    var transEndEventNames = {
      'WebkitTransition' : 'webkitTransitionEnd',
      'MozTransition'    : 'transitionend',
      'OTransition'      : 'oTransitionEnd otransitionend',
      'transition'       : 'transitionend'
    }

    for (var name in transEndEventNames) {
      if (el.style[name] !== undefined) {
        return { end: transEndEventNames[name] }
      }
    }

    return false // explicit for ie8 (  ._.)
  }


  $(function () {
    $.support.transition = transitionEnd()
  })

}(jQuery);

Observe que eles também incluem uma função emulateTransitionEnd que pode ser necessária para garantir que sempre ocorra um retorno de chamada.

  // http://blog.alexmaccaw.com/css-transitions
  $.fn.emulateTransitionEnd = function (duration) {
    var called = false, $el = this
    $(this).one($.support.transition.end, function () { called = true })
    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
    setTimeout(callback, duration)
    return this
  }

Esteja ciente de que, às vezes, esse evento não é acionado, geralmente no caso em que as propriedades não mudam ou uma pintura não é acionada. Para garantir que sempre recebamos um retorno de chamada, vamos definir um tempo limite que acionará o evento manualmente.

http://blog.alexmaccaw.com/css-transitions

Tom
fonte
3
Você não pode fazer algo assim. Em alguns casos, o callbaack será acionado mais de uma vez.
sebastian
11
Em navegadores que mantêm os nomes de evento regulares e prefixados. Você pode resolver isso usando .uma vez de .no
AlexG
61

Todos os navegadores modernos agora suportam o evento não corrigido:

element.addEventListener('transitionend', callback, false);

Funciona nas versões mais recentes do Chrome, Firefox e Safari. Mesmo IE10 +.

neave
fonte
16

No Opera 12, quando você liga usando o JavaScript simples, 'oTransitionEnd' funcionará:

document.addEventListener("oTransitionEnd", function(){
    alert("Transition Ended");
});

no entanto, se você ligar através do jQuery, precisará usar 'otransitionend'

$(document).bind("otransitionend", function(){
    alert("Transition Ended");
});

Caso esteja usando o Modernizr ou o bootstrap-transit.js, basta fazer uma alteração:

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

Você pode encontrar algumas informações aqui também http://www.ianlunn.co.uk/blog/articles/opera-12-otransitionend-bugs-and-workarounds/

Peter
fonte
6

Apenas por diversão, não faça isso!

$.fn.transitiondone = function () {
  return this.each(function () {
    var $this = $(this);
    setTimeout(function () {
      $this.trigger('transitiondone');
    }, (parseFloat($this.css('transitionDelay')) + parseFloat($this.css('transitionDuration'))) * 1000);
  });
};


$('div').on('mousedown', function (e) {
  $(this).addClass('bounce').transitiondone();
});

$('div').on('transitiondone', function () {
  $(this).removeClass('bounce');
});
yckart
fonte
3

Se você simplesmente deseja detectar apenas um único final de transição, sem usar nenhuma estrutura JS, aqui está uma pequena função de utilitário:

function once = function(object,event,callback){
    var handle={};

    var eventNames=event.split(" ");

    var cbWrapper=function(){
        eventNames.forEach(function(e){
            object.removeEventListener(e,cbWrapper, false );
        });
        callback.apply(this,arguments);
    };

    eventNames.forEach(function(e){
        object.addEventListener(e,cbWrapper,false);
    });

    handle.cancel=function(){
        eventNames.forEach(function(e){
            object.removeEventListener(e,cbWrapper, false );
        });
    };

    return handle;
};

Uso:

var handler = once(document.querySelector('#myElement'), 'transitionend', function(){
   //do something
});

se você deseja cancelar em algum momento, ainda pode fazê-lo com

handler.cancel();

Também é bom para outros usos do evento :)

OpherV
fonte