Os movimentos são uma parte essencial de qualquer experiência digital e orientam o usuário de uma interação a outra. No entanto, existem algumas lacunas nas animações suaves na plataforma Web. Isso inclui a possibilidade de animar com facilidade animações de entrada e saída, além de animações suaves de e para a camada superior para elementos dispensáveis, como caixas de diálogo e pop-ups.
Para preencher essas lacunas, o Chrome 116 e 117 incluem quatro novos recursos da plataforma da Web, que permitem animações e transições suaves para propriedades distintas.
Esses quatro novos recursos incluem:
- Capacidade de animar
display
econtent-visibility
em uma linha do tempo de frame-chave (do Chrome 116 em diante). - A propriedade
transition-behavior
com a palavra-chaveallow-discrete
para ativar transições de propriedades discretas comodisplay
(do Chrome 117) - A regra
@starting-style
para animar os efeitos de entrada dedisplay: none
para a camada superior (do Chrome 117). - A propriedade
overlay
para controlar o comportamento da camada superior durante uma animação (do Chrome 117). ## Exibir animações em frames-chave
No Chrome 116, é possível usar display
e content-visibility
nas regras de frame-chave. Eles serão alternados no momento em que o frame-chave ocorrer. Nenhum valor novo é necessário para dar suporte a esse código:
.card {
animation: fade-out 0.5s forwards;
}
@keyframes fade-out {
100% {
opacity: 0;
display: none;
}
}
O exemplo anterior anima a opacidade para 0 durante a duração de 0,5 s e, em seguida, define a exibição como nenhuma. Além disso, a palavra-chave forwards
garante que a animação permaneça no estado final, para que o elemento em que ela é aplicada permaneça display: none
e opacity: 0
.
Este é um exemplo simples que imita o que você pode fazer com uma transição (veja a demonstração na seção de transição). No entanto, as transições não conseguem criar animações mais complexas, como no exemplo a seguir:
.card {
animation: spin-and-delete 1s ease-in forwards;
}
@keyframes spin-and-delete {
0% {
transform: rotateY(0);
filter: hue-rotate(0);
}
80% {
transform: rotateY(360deg);
filter: hue-rotate(180deg);
opacity: 1;
}
100% {
opacity: 0;
display: none;
}
}
A animação spin-and-delete
é de saída. Primeiro, o card gira no eixo y, passa por uma rotação de matiz e, em 80%
, na linha do tempo, muda a opacidade de 1 para 0. Por fim, o card alterna de display: block
para display: none
.
Para essas animações de saída, em vez de aplicá-las diretamente a um elemento, você pode configurar um acionador para elas. Por exemplo, anexando um listener de eventos a um botão que aciona uma classe para aplicar a animação, desta forma:
.spin-out {
animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
document.querySelector('.card').classList.add('spin-out');
})
O exemplo acima agora tem um estado final de display:none
. Há muitos casos em que convém ir além e remover o nó DOM com um tempo limite para permitir que a animação termine primeiro.
Como fazer a transição de animações discretas
Diferente da animação de propriedades discretas com frames-chave, para fazer a transição de propriedades discretas, você precisa usar o modo de comportamento de transição allow-discrete
.
A propriedade transition-behavior
O modo allow-discrete
possibilita transições discretas e é um valor da propriedade transition-behavior
. transition-behavior
aceita dois valores: normal
e allow-discrete
.
.card {
transition: opacity 0.25s, display 0.25s;
transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}
.card.fade-out {
opacity: 0;
display: none;
}
A abreviação transition
também define esse valor. Assim, você pode omitir a propriedade e usar a palavra-chave allow-discrete
no final da abreviação transition
para cada transição.
.card {
transition: opacity 0.5s, display 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
Se você estiver animando várias propriedades discretas, será necessário incluir allow-discrete
após cada propriedade que quiser animar. Exemplo:
.card {
transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
A regra @starting-style
para animações de entrada
Até agora, este artigo abordou animações de saída. Para criar animações de entrada, é necessário usar a regra @starting-style
.
Use @starting-style
para aplicar um estilo que o navegador pode consultar antes que o elemento seja aberto na página. Este é o estado "antes de abrir" (de onde você está animando a imagem).
/* 0. BEFORE-OPEN STATE */
/* Starting point for the transition */
@starting-style {
.item {
opacity: 0;
height: 0;
}
}
/* 1. IS-OPEN STATE */
/* The state at which the element is open + transition logic */
.item {
height: 3rem;
display: grid;
overflow: hidden;
transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}
/* 2. EXITING STATE */
/* While it is deleting, before DOM removal in JS, apply this
transformation for height, opacity, and a transform which
skews the element and moves it to the left before setting
it to display: none */
.is-deleting {
opacity: 0;
height: 0;
display: none;
transform: skewX(50deg) translateX(-25vw);
}
Agora você tem um estado de entrada e de saída para estes itens da lista de tarefas:
Animar elementos de e para a camada superior
Para animar elementos de e para a camada superior, especifique o @starting-style
no estado "aberto" para informar ao navegador onde a animação será feita. Em uma caixa de diálogo, o estado aberto é definido com o atributo [open]
. Para um pop-up, use a pseudoclasse :popover-open
.
Um exemplo simples de caixa de diálogo pode ser assim:
/* 0. BEFORE-OPEN STATE */
@starting-style {
dialog[open] {
translate: 0 100vh;
}
}
/* 1. IS-OPEN STATE */
dialog[open] {
translate: 0 0;
}
/* 2. EXIT STATE */
dialog {
transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
translate: 0 100vh;
}
No próximo exemplo, os efeitos de entrada e saída são diferentes. Entre animando a partir da parte inferior da janela de visualização, saia do efeito para cima da janela de visualização. Ele também é escrito com CSS aninhado para maior encapsulamento visual.
Ao animar um pop-up, use a pseudoclasse :popover-open
em vez do atributo open
usado anteriormente.
.settings-popover {
&:popover-open {
/* 0. BEFORE-OPEN STATE */
/* Initial state for what we're animating *in* from,
in this case: goes from lower (y + 20px) to center */
@starting-style {
transform: translateY(20px);
opacity: 0;
}
/* 1. IS-OPEN STATE */
/* state when popover is open, BOTH:
what we're transitioning *in* to
and transitioning *out* from */
transform: translateY(0);
opacity: 1;
}
/* 2. EXIT STATE */
/* Initial state for what we're animating *out* to ,
in this case: goes from center to (y - 50px) higher */
transform: translateY(-50px);
opacity: 0;
/* Enumerate transitioning properties,
including display and allow-discrete mode */
transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}
Propriedade overlay
Por fim, para esmaecer uma popover
ou dialog
da camada superior, adicione a propriedade overlay
à sua lista de transições. popover
e dialog
fazem o escape de clipes e transformações ancestrais e também colocam o conteúdo na camada superior. Se você não fizer a transição de overlay
, seu elemento voltará imediatamente a ser recortado, transformado e coberto, e a transição não será feita.
[open] {
transition: opacity 1s, display 1s allow-discrete;
}
Em vez disso, inclua overlay
na transição ou na animação para animar overlay
com o restante dos recursos e garantir que ele permaneça na camada superior durante a animação. Isso será muito mais suave.
[open] {
transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}
Além disso, quando há vários elementos abertos na camada superior, a sobreposição ajuda a controlar a transição suave para dentro e para fora da camada superior. Veja a diferença neste exemplo simples. Se você não estiver aplicando overlay
ao segundo pop-up ao fazer a transição, ele primeiro sairá da camada superior, ficando atrás do outro pop-up antes de iniciar a transição. Esse efeito não é muito suave.
Observação sobre transições de visualização
Se você estiver fazendo mudanças no DOM, como adicionar e remover elementos, outra ótima solução para animações suaves são as transições de visualização. Confira dois dos exemplos acima criados com transições de visualização.
Nesta primeira demonstração, em vez de configurar @starting-style
e outras transformações CSS, as transições de visualização vão processar a transição. A transição de visualização é configurada da seguinte forma:
No CSS, primeiro atribua um view-transition-name
individual a cada card.
.card-1 {
view-transition-name: card-1;
}
.card-2 {
view-transition-name: card-2;
}
/* etc. */
Em seguida, em JavaScript, envolva a mutação do DOM (neste caso, removendo o cartão) em uma transição de visualização.
deleteBtn.addEventListener('click', () => {
// Check for browser support
if (document.startViewTransition) {
document.startViewTransition(() => {
// DOM mutation
card.remove();
});
}
// Alternative if no browser support
else {
card.remove();
}
})
Agora, o navegador pode lidar com o esmaecimento e a transformação de cada cartão para a nova posição.
Outro exemplo de onde isso pode ser útil é com a demonstração de adição/remoção de itens de lista. Nesse caso, é preciso adicionar um view-transition-name
exclusivo para cada cartão criado.
Conclusão
Esses novos recursos da plataforma nos aproximam um pouco mais das animações de entrada e saída suaves na plataforma da Web. Para saber mais, confira estes links: