By Chris Coyier
O seguinte é um post escrito por um convidado, Zach Saucier. Zach escreveu para mim dizendo-me
que, como um frequentador de fóruns de codificação como "Stack Overflow", ele vê muitas perguntas
sobre o controle de animações CSS com JavaScript, e provou mostrando-me um monte de links. Eu
estive para escrever sobre isso há muito tempo, então eu estou feliz em deixar Zach trabalhar nele e
escrever este tutorial abrangente.
Web designers às vezes acreditam que a animação em CSS é mais difícil do que em JavaScript.
Enquanto a animação CSS tem algumas limitações, na maioria das vezes é mais eficaz do que nós damos
crédito! Para não mencionar, tipicamente mais performance.
Juntamente com um toque de JavaScript, as animações CSS e transições são capazes de realizar
animações aceleradas por hardware e interações de forma mais eficiente do que a maioria das bibliotecas
JavaScript.
Transições em CSS são aplicadas a um elemento e especificam que, quando uma propriedade muda,
deve fazê-lo gradualmente ao longo de um período de tempo. As animações são diferentes. Quando
aplicadas, elas apenas executam e fazem o que lhes foi solicitado. Elas oferecem controle mais refinado,
como diferentes controles de paradas de animações.
Existem inúmeras perguntas sobre fóruns de codificação relacionados ao disparo e à pausa da transição
de um elemento. A solução é realmente muito simples usando JavaScript.
Para acionar a transição de um elemento, alterne um nome de classe nesse elemento que a ativa.
Para pausar a transição de um elemento, use "getComputedStyle" e "getPropertyValue" no ponto da
transição que você deseja pausá-lo. Em seguida, defina as propriedades CSS desses elementos igual aos
valores que você acabou de obter.
DOC HTML
<h3>Pure Javascript</h3>
<div class='box'></div>
<button class='toggleButton' value='play'>Play</button>
<h3>jQuery</h3>
<div class='box'></div>
<button class='toggleButton' value='play'>Play</button>
DOC CSS
.box {
margin: 30px;
height: 50px;
width: 50px;
background-color: blue;
}
.box.horizTranslate {
-webkit-transition: 3s;
-moz-transition: 3s;
-ms-transition: 3s;
-o-transition: 3s;
transition: 3s;
margin-left: 50% !important;
}
DOC JAVASCRIPT
var boxOne = document.getElementsByClassName('box')[0],
$boxTwo = $('.box:eq(1)');
document.getElementsByClassName('toggleButton')[0].onclick = function() {
if(this.innerHTML === 'Play')
{
this.innerHTML = 'Pause';
boxOne.classList.add('horizTranslate');
} else {
this.innerHTML = 'Play';
var computedStyle = window.getComputedStyle(boxOne),
marginLeft = computedStyle.getPropertyValue('margin-left');
boxOne.style.marginLeft = marginLeft;
boxOne.classList.remove('horizTranslate');
}
}
$('.toggleButton:eq(1)').on('click', function() {
if($(this).html() === 'Play')
{
$(this).html('Pause');
$boxTwo.addClass('horizTranslate');
} else {
$(this).html('Play');
var computedStyle = $boxTwo.css('margin-left');
$boxTwo.removeClass('horizTranslate');
$boxTwo.css('margin-left', computedStyle);
}
});
Esta mesma técnica pode ser usada de maneiras mais avançadas. O exemplo a seguir também aciona
uma transição alterando um nome de classe, mas desta vez uma variável mantém o controle da taxa de
zoom atual.
DOC HTML
<h3>Pure Javascript</h3>
<div class="zoomPic"></div>
<button class='zoom'>Zoom</button>
<button class='pause'>Pause</button>
<button class='zoomout'>Zoom Out</button>
<h3>jQuery</h3>
<div class='zoomPic'></div>
<button class='zoom'>Zoom</button>
<button class='pause'>Pause</button>
<button class='zoomout'>Zoom Out</button>
DOC CSS
.zoomPic {
margin: 30px;
width: 300px;
height: 180px;
background-color: blue;
background-image: url(http://placehold.it/1200x720);
background-repeat:no-repeat;
background-position:50% 50%;
background-size: 300px 180px;
DOC JAVASCRIPT
var zoomOne = document.getElementsByClassName('zoomPic')[0],
zoomOneBGSize = window.getComputedStyle(zoomOne).getPropertyValue('background-size'),
$zoomTwo = $('.zoomPic:eq(1)'),
zoomTwoBGSize = $zoomTwo.css('background-size');
document.getElementsByClassName('zoom')[0].onclick = function() {
if(!zoomOne.classList.contains('zoom'))
{
zoomOne.classList.add('zoom');
}
}
document.getElementsByClassName('pause')[0].onclick = function() {
var computedStyle = window.getComputedStyle(zoomOne),
backgroundSize = computedStyle.getPropertyValue('background-size');
zoomOne.style.backgroundSize = backgroundSize;
zoomOne.classList.remove('zoom');
}
document.getElementsByClassName('zoomout')[0].onclick = function() {
zoomOne.classList.remove('zoom');
zoomOne.style.backgroundSize = zoomOneBGSize;
}
$('.zoom:eq(1)').on('click', function() {
if(!$zoomTwo.hasClass('zoom'))
{
$zoomTwo.addClass('zoom');
}
});
$('.pause:eq(1)').on('click', function() {
var backgroundSize = $zoomTwo.css("background-size");
$zoomTwo.css({'background-size': backgroundSize});
$zoomTwo.removeClass('zoom');
});
$('.zoomout:eq(1)').on('click', function() {
$zoomTwo.removeClass('zoom');
$zoomTwo.css('background-size', zoomTwoBGSize);
});
Observe que estamos alterando o tamanho de fundo dessa vez. Existem muitas propriedades CSS
diferentes que podem ser transicionadas ou animadas, normalmente uma que tenha valores numéricos
ou de cor.
Alguns dos truques de JavaScript mais úteis e ainda pouco conhecidos para manipular transições de CSS
e animações são os eventos de DOM que disparam. Como: "animationend", "animationstart" e
"animationiteration" para animações e "transitionend" para transições. Você pode adivinhar o que eles
fazem. Esses eventos de animação são acionados quando a animação de um elemento termina, inicia ou
completa uma iteração, respectivamente.
Esses eventos precisam ser prefixados pelo fornecedor neste momento, então nesta demonstração,
usamos uma função desenvolvida por Craig Buckler chamada "PrefixedEvent", que tem os parâmetros
"element", "type" e "callback" para ajudar a tornar esses eventos independente de navegador.
A idéia nesta demo é ampliar o coração e parar a animação quando ela estiver pairando.
DOC HTML
<script src="http://code.jquery.com/jquery-2.0.0.js"></script>
<h3>Pure CSS</h3>
<div class='heart animated css'></div>
<h3>With Javascript</h3>
<div class='heart animated'></div>
DOC CSS
/* A maioria do CSS do desenho do coração veio das formas do CSS */
/* http://css-tricks.com/examples/ShapesOfCSS/ */
.heart {
position: relative;
width: 100px;
height: 90px;
margin: 30px;
-webkit-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
-moz-transform: scale(1);
transform: scale(1);
-webkit-transform-origin: center center;
-moz-transform-origin: center center;
-ms-transform-origin: center center;
-o-transform-origin: center center;
transition: all 1s;
}
.heart.css {
-webkit-animation-delay:1s;
-moz-animation-delay:1s;
-ms-animation-delay:1s;
-o-animation-delay:1s;
animation-dely:1s;
}
.heart.animated {
-webkit-animation: 1600ms pulsate infinite alternate ease-in-out;
-moz-animation: 1600ms pulsate infinite alternate ease-in-out;
-ms-animation: 1600ms pulsate infinite alternate ease-in-out;
-o-animation: 1600ms pulsate infinite alternate ease-in-out;
animation: 1600ms pulsate infinite alternate ease-in-out;
}
.heart:before,
.heart:after {
position: absolute;
content: "";
left: 50px;
top: 0;
width: 50px;
height: 80px;
background: red;
-moz-border-radius: 50px 50px 0 0;
border-radius: 50px 50px 0 0;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-transform-origin: 0 100%;
-moz-transform-origin: 0 100%;
-ms-transform-origin: 0 100%;
-o-transform-origin: 0 100%;
transform-origin: 0 100%;
}
.heart:after {
left: 0;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transform-origin: 100% 100%;
-moz-transform-origin: 100% 100%;
-ms-transform-origin: 100% 100%;
-o-transform-origin: 100% 100%;
transform-origin :100% 100%;
}
.heart.css:hover {
-webkit-transform: scale(2);
-moz-transform: scale(2);
-ms-transform: scale(2);
-o-transform: scale(2);
transform: scale(2);
-webkit-animation:'';
-moz-animation:none;
-ms-animation:'';
-o-animation:'';
animation:'';
}
@keyframes pulsate {
0% { transform: scale(1); }
50% { transform: scale(1.3); }
100% { transform: scale(1); }
}
@-webkit-keyframes pulsate {
0% { -webkit-transform: scale(1); }
50% { -webkit-transform: scale(1.3); }
100% { -webkit-transform: scale(1); }
}
@-moz-keyframes pulsate {
0% { -moz-transform: scale(1); }
50% { -moz-transform: scale(1.3); }
100% { -moz-transform: scale(1); }
}
@-ms-keyframes pulsate {
0% { -ms-transform: scale(1); }
50% { -ms-transform: scale(1.3); }
100% { -ms-transform: scale(1); }
}
@-o-keyframes pulsate {
0% { -o-transform: scale(1); }
50% { -o-transform: scale(1.3); }
100% { -o-transform: scale(1); }
}
DOC JAVASCRIPT
var heart = document.getElementsByClassName('heart')[1],
pfx = ["webkit", "moz", "MS", "o", ""],
hovered = false;
function AnimationListener() {
if(hovered)
{
heart.classList.remove('animated');
heart.style.webkitTransform = 'scale(2)';
heart.style.MozTransform = 'scale(2)';
heart.style.msTransform = 'scale(2)';
heart.style.OTransform = 'scale(2)';
heart.style.transform = 'scale(2)';
}
}
function TransitionListener() {
if(!hovered)
{
heart.classList.add('animated');
}
}
function PrefixedEvent(element, type, callback) {
for (var p = 0; p < pfx.length; p++) {
if (!pfx[p]) type = type.toLowerCase();
element.addEventListener(pfx[p]+type, callback, false);
}
}
heart.onmouseover = function() {
hovered = true;
}
heart.onmouseout = function() {
setTimeout(function() { hovered = false; }, 500);
PrefixedEvent(heart, "TransitionEnd", TransitionListener);
heart.style.webkitTransform = 'scale(1)';
heart.style.MozTransform = 'scale(1)';
heart.style.msTransform = 'scale(1)';
heart.style.OTransform = 'scale(1)';
heart.style.transform = 'scale(1)';
}
A versão CSS pura é jumpy. A menos que você passe o mouse sobre ele no momento perfeito, ele saltará
para um estado particular antes de aumentar para o estado final pairado. A versão JavaScript é muito
mais suave. Remove o salto deixando a animação completa antes de aplicar o novo estado.
A propriedade animation-play-state
element.style.webkitAnimationPlayState = "paused";
element.style.webkitAnimationPlayState = "running";
Infelizmente, neste momento, não há nenhuma maneira de obter a exata atual "porcentagem concluída"
de uma animação de quadro-chave (KeyFrame) CSS. O melhor método para aproximá-lo é usando uma
função "setInterval" que itera 100 vezes durante a animação, que é essencialmente: a duração da
animação em ms / 100. Por exemplo, se a animação é de 4 segundos, então o "setInterval" precisa ser
executado a cada 40 Milissegundos (4000/100).
Esta abordagem está longe de ser ideal, porque a função realmente é executada com menos freqüência
do que a cada 40 milissegundos. Acho que configurá-lo para 39 milissegundos é mais preciso, mas
confiar nisso é má prática, como provavelmente varia de navegador para navegador e não é um ajuste
perfeito em todos os navegadores.
Em um mundo perfeito, seríamos capazes de selecionar um elemento que está usando uma animação
CSS, remover essa animação e dar-lhe uma nova. Em seguida, começaria a nova animação, a partir de
seu estado atual. Nós não vivemos nesse mundo perfeito, então é um pouco mais complexo.
Abaixo temos uma demonstração para testar uma técnica de obtenção e alteração de uma animação CSS
"mid stream", por assim dizer. A animação move um elemento em um caminho circular com a posição
de início sendo no centro superior ( "doze horas", se preferir) Quando o botão é clicado, ele deve alterar
a posição inicial da animação para a localização atual do elemento . Ele viaja o mesmo caminho, só que
agora "começa" no local em que estava quando você apertou o botão. Essa mudança de origem e,
portanto, mudança de animação, é indicada pela alteração da cor do elemento para vermelho no
primeiro quadro-chave.
DOC HTML
<! - Observação: este exemplo só funciona em Navegadores Webkit ->
<div id="circle"></div>
<div id='button'>ChangeAnimation</div>
<div id='result'></div>
DOC CSS
@-webkit-keyframes rotate {
0% {
-webkit-transform:translate(100px, 100px) rotate(0deg) translate(-100px, -100px) rotate(0deg);
background-color:red;
}
13% {
-webkit-transform:translate(100px, 100px) rotate(45deg) translate(-100px, -100px) rotate(-
45deg);
}
25% {
-webkit-transform:translate(100px, 100px) rotate(90deg) translate(-100px, -100px) rotate(-90deg);
}
38% {
-webkit-transform:translate(100px, 100px) rotate(135deg) translate(-100px, -100px) rotate(0deg);
}
50% {
-webkit-transform:translate(100px, 100px) rotate(180deg) translate(-100px, -100px) rotate(-
180deg);
}
63% {
-webkit-transform:translate(100px, 100px) rotate(225deg) translate(-100px, -100px)
rotate(225deg);
}
75% {
-webkit-transform:translate(100px, 100px) rotate(270deg) translate(-100px, -100px) rotate(-
270deg);
}
88% {
-webkit-transform:translate(100px, 100px) rotate(315deg) translate(-100px, -100px)
rotate(315deg);
}
100% {
-webkit-transform:translate(100px, 100px) rotate(360deg) translate(-100px, -100px) rotate(-
360deg);
}
}
#circle {
height: 50px;
width: 50px;
border-radius:25px;
background-color: teal;
-webkit-animation-duration: 4s;
-webkit-animation-timing-function: linear;
-webkit-animation-name:"rotate";
-webkit-animation-iteration-count: infinite;
position:absolute;
left:30%;
top:20%;
}
#button {
width:130px;
background:teal;
}
DOC JAVASCRIPT
// Verifica se a regra especificada está dentro de qualquer uma das folhas de estilo encontradas no
documento; Retorna o objeto de animação se assim for
function findKeyframesRule(rule) {
var ss = document.styleSheets;
for (var i = 0; i < ss.length; ++i) {
for (var j = 0; j < ss[i].cssRules.length; ++j) {
if (ss[i].cssRules[j].type == window.CSSRule.WEBKIT_KEYFRAMES_RULE &&
ss[i].cssRules[j].name == rule) { return ss[i].cssRules[j]; }
}
}
return null;
}
// Substitui a animação com base na porcentagem quando ativada e outras especificações codificadas
function change(anim) {
// Obtém o objeto de animação da animação especificada
var keyframes = findKeyframesRule(anim),
length = keyframes.cssRules.length;
// Remove todos os valores (%) da matriz para que a função "getClosest" possa executar cálculos
var keys = keyframeString.map(function(str) {
return str.replace('%', '');
});
// Essencialmente, isso cria as regras para definir uma nova origem para o caminho com base no
percentual aproximado da animação quando ativado e aumenta o diâmetro do novo caminho circular
keyframes.insertRule("0% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 0) +
"deg) translate(-100px,-100px) rotate(" + (multiplier + 0) + "deg); background-color:red; }");
keyframes.insertRule("13% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 45) +
"deg) translate(-100px,-100px) rotate(" + (multiplier + 45) + "deg); }");
keyframes.insertRule("25% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 90) +
"deg) translate(-100px,-100px) rotate(" + (multiplier + 90) + "deg); }");
keyframes.insertRule("38% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 135)
+ "deg) translate(-100px,-100px) rotate(" + (multiplier + 135) + "deg); }");
keyframes.insertRule("50% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 180)
+ "deg) translate(-100px,-100px) rotate(" + (multiplier + 180) + "deg); }");
keyframes.insertRule("63% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 225)
+ "deg) translate(-100px,-100px) rotate(" + (multiplier + 225) + "deg); }");
keyframes.insertRule("75% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 270)
+ "deg) translate(-100px,-100px) rotate(" + (multiplier + 270) + "deg); }");
keyframes.insertRule("88% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 315)
+ "deg) translate(-100px,-100px) rotate(" + (multiplier + 315) + "deg); }");
keyframes.insertRule("100% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 360)
+ "deg) translate(-100px,-100px) rotate(" + (multiplier + 360) + "deg); }");
// Obtém o valor de (%) mais próximo da animação com base na (%) aproximada encontrada abaixo
function getClosest(keyframe) {
var curr = keyframe[0];
var diff = Math.abs (totalCurrentPercent - curr);
for (var val = 0, j = keyframe.length; val < j; val++) {
var newdiff = Math.abs(totalCurrentPercent - keyframe[val]);
if (newdiff < diff ) {
diff = newdiff;
curr = keyframe[val];
}
}
return curr;
}
Nós vamos ter que cavar na própria folha de estilos para encontrar a animação original. Você pode
acessar as folhas de estilo associadas a uma página usando "document.styleSheets" e iterar através dela
usando um "loop for". O exemplo seguinte é sobre como você pode usar JavaScript para localizar valores
de uma determinada animação em um objeto "CSSKeyFrameRules":
function findKeyframesRule(rule) {
var ss = document.styleSheets;
for (var i = 0; i < ss.length; ++i) {
for (var j = 0; j < ss[i].cssRules.length; ++j) {
if (ss[i].cssRules[j].type == window.CSSRule.WEBKIT_KEYFRAMES_RULE &&
ss[i].cssRules[j].name == rule) {
return ss[i].cssRules[j]; }
}
}
return null;
}
Uma vez que chamamos a função acima (por exemplo, var keyframes = findKeyframesRule (anim)),
você pode obter o comprimento da animação do objeto (o número total de quantos quadros-chave há
nessa animação) usando "keyframes.cssRules.length". Então precisamos tirar a "%" de cada um dos
quadros-chave para que eles sejam apenas números e JavaScript pode usá-los como números. Para fazer
isso, usamos o seguinte exemplo, que usa o método ".map" do JavaScript.
// Remove todos os valores (%) da matriz para que a função "getClosest" possa executar cálculos
var keys = keyframeString.map(function(str) {
return str.replace('%', '');
});
Neste ponto, as chaves serão uma matriz de todos os quadros-chave da animação em formato numérico.
No caso de nossa demonstração de animação circular, precisamos de duas variáveis: uma para rastrear
quantos graus o círculo havia percorrido desde sua localização de início mais recente e outra para
rastrear quantos graus havia percorrido desde o local de início original. Podemos mudar a primeira
variável usando nossa função "setInterval" (usando o tempo decorrido em graus em um círculo). Então
podemos usar o seguinte código para atualizar a segunda variável quando o botão é clicado.
totalCurrentPercent += currentPercent;
// Uma vez que é em porcentagem não deve nunca ser mais de 100
if (totalCurrentPercent > 100) {
totalCurrentPercent -= 100;
}
Então, podemos usar a seguinte função para descobrir qual quadro-chave da animação está mais
próximo da porcentagem atual total, com base na matriz de possíveis percentuais de quadros-chave
obtidos acima.
function getClosest(keyframe) {
// "curr" representa o quadro-chave atual
var curr = keyframe[0];
var diff = Math.abs (totalCurrentPercent - curr);
for (var val = 0, j = keyframe.length; val < j; val++) {
var newdiff = Math.abs(totalCurrentPercent - keyframe[val]);
// Se a diferença entre a porcentagem atual e o quadro-chave iterado for menor, leva a nova diferença
(newdiff ) e o quadro-chave
if (newdiff < diff ) {
diff = newdiff;
curr = keyframe[val];
}
}
return curr;
}
Para obter o primeiro valor de quadro-chave da nova animação para uso nos cálculos posteriores,
podemos usar o método ".indexOf" do JavaScript. Em seguida, excluímos os quadros-chave originais
para que possamos recriar novos.
Em seguida, precisamos mudar a (%) em um graus do círculo. Podemos fazer isso simplesmente
multiplicando a nova primeira porcentagem por 3,6 (porque 10 0 * 3,6 = 360).
Finalmente, criamos as novas regras com base nas variáveis obtidas acima. A diferença de 45 graus entre
cada regra é porque temos 8 quadros-chave diferentes que circundam o círculo. 360 (graus em um
círculo) dividido por 8 é 45.
keyframes.insertRule("0% {
-webkit-transform: translate(100px, 100px) rotate(" + (multiplier + 0) + "deg)
translate(-100px, -100px) rotate(" + (multiplier + 0) + "deg);
background-color:red;
}");
keyframes.insertRule("13% {
-webkit-transform: translate(100px, 100px) rotate(" + (multiplier + 45) + "deg)
translate(-100px, -100px) rotate(" + (multiplier + 45) + "deg);
}");
...continued...
Em seguida, redefinimos a porcentagem atual "setInterval" para que ela possa ser executada novamente.
Observe que o acima é WebKit prefixado. Para torná-lo mais compatível com cross-browser você
poderia fazer algum algoritmo de busca (sniffing UA) para adivinhar quais prefixos seriam necessários:
Como vimos, manipular transições CSS pode ser simplificado usando JavaScript. Se você não acabar
recebendo os resultados desejados com animações CSS, você pode tentar torná-la uma transição e
trabalhar com ela dessa forma. Elas têm a mesma dificuldade de codificar, mas podem ser mais
facilmente definidas e editadas.
Relacionando isso com nossa demo de rotação, um pequeno truque é multiplicar tanto a transição-
duração e a rotação por "x". Então você precisa ter / aplicar uma classe para acionar a animação, porque
se você aplicar as propriedades alteradas diretamente para o elemento, bem, não haverá muito de uma
transição a ser visto. Para iniciar a transição (animação falsa), você aplica a classe ao elemento.
DOC HTML
<h3>Mas ... Qual é a animação?</h3>
<div class='rotator animation'></div>
DOC CSS
.rotator {
width: 100px;
height: 100px;
margin: 20px;
background-color:teal;
}
.transition {
-webkit-transition: all 1000s linear;
-moz-transition: all 1000s linear;
-ms-transition: all 1000s linear;
-o-transition: all 1000s linear;
transition: all 1000s linear;
}
.translateAnimationClass {
-webkit-transform: rotateX(43200deg) rotateY(14400deg);
-moz-transform: rotateX(43200deg) rotateY(14400deg);
-ms-transform: rotateX(43200deg) rotateY(14400deg);
-o-transform: rotateX(43200deg) rotateY(14400deg);
transform: rotateX(43200deg) rotateY(14400deg);
}
.animation {
-webkit-animation: rotator 25s linear infinite;
-moz-animation: rotator 25s linear infinite;
-ms-animation: rotator 25s linear infinite;
-o-animation: rotator 25s linear infinite;
animation: rotator 25s linear infinite;
}
@-webkit-keyframes rotator {
0% { -webkit-transform: rotateX(0deg) rotateY(0deg); }
100% { -webkit-transform: rotateX(1080deg) rotateY(360deg); }
}
@-moz-keyframes rotator {
0% { -moz-transform: rotateX(0deg) rotateY(0deg); }
100% { -moz-transform: rotateX(1080deg) rotateY(360deg); }
}
@-ms-keyframes rotator {
0% { -ms-transform: rotateX(0deg) rotateY(0deg); }
100% { -ms-transform: rotateX(1080deg) rotateY(360deg); }
}
@-o-keyframes rotator {
0% { -o-transform: rotateX(0deg) rotateY(0deg); }
100% { -o-transform: rotateX(1080deg) rotateY(360deg); }
}
@keyframes rotator {
0% { transform: rotateX(0deg) rotateY(0deg); }
100% { transform: rotateX(1080deg) rotateY(360deg); }
}
DOC JAVASCRIPT
window.onload = function() { document.getElementsByClassName('transition')
[0].classList.add('translateAnimationClass'); }
Manipular animações CSS também pode ser feito usando um "CSSMatrix". Por exemplo:
var translated3D =
new WebKitCSSMatrix(window.getComputedStyle(elem, null).webkitTransform);
Antes de começar a codificar, pensar e planejar como uma transição ou animação deve ser executada é a
melhor maneira de minimizar seus problemas e obter o efeito desejado. As técnicas e os truques
descritos neste artigo podem não ser sempre a melhor maneira de criar a animação que o seu projeto
solicita.
Aqui está um pequeno exemplo de onde ficar inteligente com HTML e CSS sozinho pode resolver um
problema onde você pode ter pensado em ir para JavaScript.
Digamos que queremos um gráfico para girar continuamente e, em seguida, mudar de direção de
rotação quando o mouse passar sobre ele. Aprendendo o que foi abordado neste artigo, você pode
querer entrar e usar um evento "animationIteration" para alterar a animação. No entanto, uma solução
mais eficiente e de melhor desempenho pode ser encontrada usando CSS e um elemento de recipiente
adicionado.
O truque seria fazer com que a espiral gire em velocidade "x" em uma direção e, quando o mouse passar
sobre ela, fazer o elemento pai girar a uma velocidade "2x" na direção oposta (começando na mesma
posição). As duas rotações que trabalham uma contra a outra criam um efeito líquido da espiral girando
na direcção oposta.
DOC HTML
<!-- NOTA: No Chrome existe uma breve falha durante a transição após a primeira -->
<div class='spiralContainer'><div class='spiral'></div></div>
DOC CSS
.spiralContainer {
border-radius: 50%;
width:200px;
height:200px;
overflow:hidden;
margin:20px;
-webkit-animation-play-state: paused;
-moz-animation-play-state: paused;
-ms-animation-play-state: paused;
-o-animation-play-state: paused;
animation-play-state: paused;
}
.spiral {
width:200px;
height:200px;
border-radius: 50%;
background-image: url(http://farm7.staticflickr.com/6115/6319704650_0a2bd0dcef_o.jpg);
background-repeat:no-repeat;
background-position:50% 50%;