Curso de CSS / Animações com keyframes: direção, fill-mode e pausa

As animações keyframe de CSS descrevem valores de propriedades ao longo da linha do tempo de uma animação e podem ser executadas sem um gatilho de hover ou foco. Duração, atraso, contagem de iterações, modo de preenchimento e estado de reprodução controlam diferentes partes desse comportamento.

Distinga transições e animações keyframe

Critério transição animação
condição inicial Quando o valor muda devido a hover, foco, mudança de classe, etc. Após a animação ser aplicada e o tempo de atraso ter passado,
definição de estado Valores CSS antes e depois da mudança Especifique os valores inicial, intermediário e final nos keyframes
repetição e direção Prossiga com as mudanças de estado Especifique separadamente o número de vezes, direção e status de parada

A transição é simples, contanto que a cor de fundo do botão mude. Você pode observar animações para efeitos como quando uma notificação aparece pela primeira vez ou para uma explicação visual que passa por várias etapas. Controlar a mesma propriedade no mesmo elemento com duas funções simultaneamente torna difícil acompanhar qual valor está sendo aplicado, então, para este exercício, dividimos os papéis. Se os efeitos antes e depois da mudança de estado forem suficientes, considere começar com uma transição simples usando as Transformações e Transições do CSS.

Defina os keyframes e as configurações de reprodução

No keyframe, from corresponde a 0%, e to corresponde a 100%. Se você precisar de um estado intermediário, adicione uma porcentagem de progresso como 50%. Apenas declarar um nome de keyframe não fará com que ele seja executado; você deve associá-lo com o animation-name do elemento.

@keyframes travel {
  0% { transform: translateX(0); }
  50% { transform: translateX(3rem); }
  100% { transform: translateX(6rem); }
}
.marker { animation: travel 4s linear 1s 1 normal forwards; }

Este código parcial é uma versão resumida do keyframe e da configuração .marker com o mesmo nome no exemplo completo abaixo. 4s é o tempo que leva para ser reproduzido uma vez e 1s é o atraso de inicialização. Se a duração não for especificada, o valor padrão é 0 segundos, tornando difícil observar o processo de movimento. Você pode reduzir a confusão sobre tempo e frequência dividindo em propriedades detalhadas a princípio.

Propriedade Valores para este exemplo Coisas para mudar
animation-duration 4s um tempo de reprodução
animation-timing-function linear Diferença entre progresso constante e curva ease
animation-delay 1s Tempo de espera antes de começar
animation-iteration-count 1 Número de reproduções; infinite repete sem limite
animation-direction normal Reprodução para frente/para trás/alternada
animation-fill-mode forwards Valor a aplicar durante o tempo fora de reprodução
animation-play-state Padrão running Pausar o progresso atual com paused

Mesmo que as porcentagens dos keyframes sejam igualmente espaçadas, a mudança real na posição variará em função do tempo. Este exercício usa linear, que facilita verificar posições intermediárias. Para criação e conexão de keyframes, consulte o documento MDN @keyframes.

Compare a direção, o número de iterações e o modo de preenchimento

normal prossegue do início ao fim, e reverse prossegue do fim ao início. alternate toca alternadamente na direção direta na primeira vez e na direção inversa na próxima vez. Se animation-iteration-count for 2 e animation-direction for alternate, a última chegará ao primeiro keyframe.

forwards não significa conservar sempre o keyframe de 100%. Dependendo da direção da reprodução e do número de vezes, o valor do último keyframe realmente alcançado é mantido. No exemplo, uma vez na direção para frente mantém a posição 6rem, uma vez na direção reversa mantém a posição 0, e duas vezes na direção alternada também mantém a posição 0. Esta descrição é baseada em um número inteiro de reproduções completas; um número fracionário pode terminar no meio do progresso. a descrição de animation-fill-mode na MDN, com as condições de cada direção .

fill-mode Atrasando Após terminar
none CSS básico CSS básico
forwards CSS básico Último keyframe reproduzido
backwards Primeiro keyframe relevante para a direção CSS básico
both Primeiro keyframe relevante para a direção Último keyframe reproduzido

Se o valor CSS base e o valor do quadro-chave final forem iguais, a diferença entre none e forwards pode ser invisível. A caixa de movimento abaixo tem uma posição padrão de 1rem, um início de 0 e um fim de 6rem para revelar a diferença. Por outro lado, o aviso importante usa como estilo base um estado visível, que permanece quando a animação é removida.

Execute e altere uma configuração por vez

Salve o código a seguir como animation-lab.html em UTF-8 e abra-o no seu navegador. O aviso superior faz uma breve animação de entrada e continua visível, e a caixa decorativa inferior começa a se mover após 1 segundo e se move por 4 segundos. Depois de modificar os valores, salve o arquivo e recarregue a página para comparar desde o início.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Keyframes and end states exercise</title>
  <style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; padding: 1rem; color: #183044; font-family: sans-serif; line-height: 1.6; }
main { max-width: 46rem; margin-inline: auto; }
h1 { font-size: 1.5rem; } h2 { font-size: 1.2rem; }
button, input { font: inherit; }
button { cursor: pointer; }
:focus-visible { outline: 3px solid #164f73; outline-offset: 3px; }
.notice { padding: 1rem; border: 1px solid #90bdd8; border-radius: .5rem; background: #eaf4fa;
  opacity: 1; transform: none; animation: appear 400ms ease-out; }
@keyframes appear {
  from { opacity: 0; transform: translateY(.5rem); }
  to { opacity: 1; transform: translateY(0); }
}
.track { margin-block: 1rem; padding: 1rem; border: 2px dashed #8a9ba7; }
.marker { width: 2rem; height: 2rem; border-radius: .25rem; background: #166b92;
  transform: translateX(1rem);
  animation-name: travel; animation-duration: 4s; animation-timing-function: linear;
  animation-delay: 1s; animation-iteration-count: 1; animation-direction: normal;
  animation-fill-mode: forwards; }
@keyframes travel {
  0% { transform: translateX(0); background-color: #166b92; }
  50% { transform: translateX(3rem); background-color: #6a3989; }
  100% { transform: translateX(6rem); background-color: #28633b; }
}
#pause:checked ~ .track .marker { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .notice, .marker { animation: none; }
}
  </style>
</head>
<body>
<main>
<h1>Check entrance and movement</h1>
<p class="notice">This notice remains readable without animation.</p>
<h2>Comparing end states</h2>
<p>Movement starts one second after loading. Refresh the page to compare again.</p>
<input id="pause" type="checkbox"><label for="pause">Pause movement</label>
<div class="track"><div class="marker" aria-hidden="true"></div></div>
<p>The colors and movement are decorative. Essential information remains available independently of the animation, as in this sentence.</p>
</main>
</body>
</html>
  1. Nas configurações padrão, a caixa está na posição 1rem durante o atraso, move-se para 0 no início e permanece na posição 6rem ao terminar. Verifique a diferença entre o valor do atraso e o valor inicial.
  2. Altere apenas animation-fill-mode para none e atualize. Uma vez concluído, retorna à posição padrão de 1rem e à cor azul padrão. Restaure para forwards.
  3. Altere apenas fill-mode para both. A posição inicial 0 se aplica mesmo durante os atrasos. Após a confirmação, retorne para forwards.
  4. Deixe a contagem como 1 e altere a direção para reverse. Após a conclusão, verifique se a posição 0 permanece e restaure para normal.
  5. Verifique os resultados alterando a direção para alternate e mantendo a contagem em 1. Nesse estado, se você mudar o número para 2, ocorrerá uma segunda reprodução. Após a confirmação, a contagem será 1 e restaure a direção para normal.
  6. Imediatamente após atualizar, marque a caixa de seleção Pause movement (pausar movimento) e espere um momento. Se você cancelá-la, continuará de onde parou. Isso é diferente da capacidade de reproduzir novamente desde o início.

Mantenha o conteúdo visível com movimentos reduzidos

A configuração reduzida remove a animação das caixas de orientação e decoração. As instruções ainda são legíveis, pois o padrão é opacity: 1 e a caixa aparece na posição padrão de 1rem. Deixar o estado legível apenas nos keyframes finais ou em forwards pode fazer com que o conteúdo desapareça na ausência de animação.

Ative a redução de movimento no painel de Renderização do DevTools ou no sistema operacional e recarregue. Ambos os elementos devem permanecer imóveis enquanto seu conteúdo continua visível. Consulte o guia MDN prefers-reduced-motion, depois restaure a configuração de emulação após a comparação. Também siga Verificar layout responsivo: largura, zoom e teclado para checar corte e usabilidade com o movimento desativado.

Antes de adicionar repetição infinita, decida por que o movimento é necessário e como ele será interrompido. Este exemplo usa iterações finitas e fornece informações importantes independentemente do movimento e da cor. Se nada se mover, verifique o nome da animação, a duração e a condição de movimento reduzido. Para um estado final inesperado, compare a direção, a contagem de iterações, o modo de preenchimento e o CSS subjacente.