Imagine o seguinte: você ingressa em um novo projeto, mergulha na base de código e, nas primeiras horas, descobre algo frustrantemente familiar. Espalhadas pelas folhas de estilo, você encontra várias definições de @keyframes para as mesmas animações básicas. Três efeitos de fade-in diferentes, duas ou três variações de slide, um punhado de animações de zoom e pelo menos duas animações de rotação diferentes porque, bem, por que não? @keyframes pulso { de { escala: 1; } para { escala: 1,1; } }

@keyframes pulso maior { 0%, 20%, 100% { escala: 1; } 10%, 40% { escala: 1,2; } }

Se este cenário lhe parece familiar, você não está sozinho. Na minha experiência em vários projetos, um dos ganhos rápidos mais consistentes que posso oferecer é a consolidação e padronização de quadros-chave. Tornou-se um padrão tão confiável que agora estou ansioso por essa limpeza como uma das minhas primeiras tarefas em qualquer nova base de código. A lógica por trás do caos Essa redundância faz todo o sentido quando você pensa sobre isso. Todos nós usamos as mesmas animações fundamentais em nosso trabalho diário: fades, slides, zooms, spins e outros efeitos comuns. Essas animações são bastante diretas e é fácil criar uma definição rápida de @keyframes para realizar o trabalho. Sem um sistema de animação centralizado, os desenvolvedores naturalmente escrevem esses quadros-chave do zero, sem saber que já existem animações semelhantes em outras partes da base de código. Isso é especialmente comum ao trabalhar em arquiteturas baseadas em componentes (o que a maioria de nós faz atualmente), já que as equipes geralmente trabalham em paralelo em diferentes partes do aplicativo. O resultado? Caos de animação. O pequeno problema Os problemas mais óbvios com a duplicação de quadros-chave são o desperdício de tempo de desenvolvimento e o inchaço desnecessário do código. Várias definições de quadro-chave significam vários locais para atualização quando os requisitos mudam. Precisa ajustar o tempo da sua animação fade? Você precisará localizar todas as instâncias em sua base de código. Quer padronizar as funções de flexibilização? Boa sorte em encontrar todas as variações. Essa multiplicação de pontos de manutenção torna até mesmo simples atualizações de animação uma tarefa demorada. O maior problema Essa duplicação de quadros-chave cria um problema muito mais insidioso que se esconde abaixo da superfície: a armadilha do escopo global. Mesmo ao trabalhar com arquiteturas baseadas em componentes, os quadros-chave CSS são sempre definidos no escopo global. Isso significa que todos os quadros-chave se aplicam a todos os componentes. Sempre. Sim, sua animação não usa necessariamente os quadros-chave definidos em seu componente. Ele usa os últimos quadros-chave que correspondem exatamente ao mesmo nome que foram carregados no escopo global. Contanto que todos os seus quadros-chave sejam idênticos, isso pode parecer um problema menor. Mas no momento em que você deseja personalizar uma animação para um caso de uso específico, você terá problemas ou, pior, será você quem os causará. Ou sua animação não funcionará porque outro componente foi carregado depois do seu, substituindo seus quadros-chave, ou seu componente foi carregado por último e acidentalmente alterou o comportamento da animação para todos os outros componentes usando o nome desse quadro-chave, e você pode nem perceber. Aqui está um exemplo simples que demonstra o problema: .componente-um { /* estilos de componentes */ animação: alternância infinita de facilidade de entrada e saída de pulso 1s; }

/* esta definição de @keyframes não funcionará */ @keyframes pulso { de { escala: 1; } para { escala: 1,1; } }

/* mais tarde no código... */

.componente-dois { /* estilos de componentes */ animação: pulso 1s facilidade de entrada infinita; }

/* esses quadros-chave serão aplicados a ambos os componentes */ @keyframes pulso { 0%, 20%, 100% { escala: 1; } 10%, 40% { escala: 1,2; } }

Ambos os componentes usam o mesmo nome de animação, mas a segunda definição de @keyframes substitui a primeira. Agora, tanto o componente um quanto o componente dois usarão os segundos quadros-chave, independentemente de qual componente definiu quais quadros-chave. Veja os Pen Keyframes Tokens - Demo 1 [bifurcado] por Amit Sheen. A pior parte? Isso geralmente funciona perfeitamente no desenvolvimento local, mas quebra misteriosamente na produção quando os processos de construção alteram a ordem de carregamento das suas folhas de estilo. Você acaba com animações que se comportam de maneira diferente dependendo de quais componentes são carregados e em que sequência. A solução: quadros-chave unificados A resposta para esse caos é surpreendentemente simples: quadros-chave dinâmicos predefinidos armazenados em uma folha de estilo compartilhada. Em vez de deixar cada componente definir suas próprias animações, criamos quadros-chave centralizados que são bem documentados, fáceis deutilizável, sustentável e adaptado às necessidades específicas do seu projeto. Pense nisso como tokens de quadros-chave. Assim como usamos tokens para cores e espaçamento, e muitos de nós já usamos tokens para propriedades de animação, como funções de duração e atenuação, por que não usar tokens também para quadros-chave? Essa abordagem pode se integrar naturalmente a qualquer fluxo de trabalho de token de design atual que você esteja usando, ao mesmo tempo que resolve tanto o problema pequeno (duplicação de código) quanto o problema maior (conflitos de escopo global) de uma só vez. A ideia é simples: criar uma única fonte de verdade para todas as nossas animações comuns. Esta folha de estilo compartilhada contém quadros-chave cuidadosamente elaborados que cobrem os padrões de animação que nosso projeto realmente usa. Chega de adivinhar se uma animação fade já existe em algum lugar de nossa base de código. Chega de substituir acidentalmente animações de outros componentes. Mas aqui está a chave: não são apenas animações estáticas de copiar e colar. Eles foram projetados para serem dinâmicos e personalizáveis ​​por meio de propriedades personalizadas de CSS, permitindo-nos manter a consistência e ao mesmo tempo ter a flexibilidade de adaptar animações a casos de uso específicos, como se você precisasse de uma animação de “pulso” um pouco maior em um só lugar. Construindo o primeiro token de quadros-chave Um dos primeiros frutos que devemos enfrentar é a animação “fade-in”. Em um dos meus projetos recentes, encontrei mais de uma dúzia de definições separadas de fade-in e, sim, todas elas simplesmente animaram a opacidade de 0 a 1. Então, vamos criar uma nova folha de estilo, chamá-la de kf-tokens.css, importá-la para nosso projeto e colocar nossos quadros-chave com os comentários apropriados dentro dela. /* quadros-chave-tokens.css */

/* * Fade In - animação de entrada fade * Uso: animação: kf-fade-in 0,3s de facilidade; */ @keyframes kf-fade-in { de { opacidade: 0; } para { opacidade: 1; } }

Esta única declaração @keyframes substitui todas as animações de fade-in espalhadas em nossa base de código. Limpo, simples e aplicável globalmente. E agora que temos esse token definido, podemos usá-lo em qualquer componente do nosso projeto: .modal { animação: kf-fade-in 0,3s de atenuação; }

.tooltip { animação: kf-fade-in 0,2s de facilidade de entrada; }

.notificação { animação: kf-fade-in 0,5s de atenuação; }

Veja os Pen Keyframes Tokens - Demo 2 [bifurcado] de Amit Sheen. Nota: estamos usando um prefixo kf- em todos os nossos nomes @keyframes. Este prefixo serve como um namespace que evita conflitos de nomenclatura com animações existentes no projeto e deixa imediatamente claro que esses quadros-chave vêm de nosso arquivo de tokens de quadros-chave. Fazendo um slide dinâmico Os quadros-chave kf-fade-in funcionam muito bem porque são simples e há pouco espaço para bagunçar as coisas. Em outras animações, entretanto, precisamos ser muito mais dinâmicos, e aqui podemos aproveitar o enorme poder das propriedades personalizadas do CSS. É aqui que os tokens de quadros-chave realmente brilham em comparação com animações estáticas dispersas. Vejamos um cenário comum: animações “slide-in”. Mas deslize de onde? 100px da direita? 50% da esquerda? Deve entrar pelo topo da tela? Ou talvez flutue do fundo? Tantas possibilidades, mas em vez de criar quadros-chave separados para cada direção e cada variação, podemos construir um token flexível que se adapta a todos os cenários: /* * Slide In - animação de slide direcional * Use --kf-slide-from para controlar a direção * Padrão: desliza da esquerda (-100%) * Uso: * animação: kf-slide-in 0,3s de facilidade; * --kf-slide-from: -100px 0; // desliza da esquerda * --kf-slide-from: 100px 0; // desliza da direita * --kf-slide-from: 0 -50px; // desliza de cima */

@keyframes kf-slide-in { de { traduzir: var(--kf-slide-from, -100% 0); } para { traduzir: 0 0; } }

Agora podemos usar este único token @keyframes para qualquer direção de slide simplesmente alterando a propriedade personalizada --kf-slide-from: .barra lateral { animação: kf-slide-in 0,3s de atenuação; /* Usa valor padrão: slides da esquerda */ }

.notificação { animação: kf-slide-in 0,4s de atenuação; --kf-slide-from: 0 -50px; /* desliza de cima para baixo */ }

.modal { animação: kf-fade-in 0,5s, kf-slide-in 0,5s cúbico-bézier (0,34, 1,56, 0,64, 1); --kf-slide-from: 50px 50px; /* desliza do canto inferior direito */ }

Essa abordagem nos dá uma flexibilidade incrível, mantendo a consistência. Uma declaração de quadro-chave, possibilidades infinitas. Veja os Pen Keyframes Tokens - Demo 3 [bifurcado] de Amit Sheen. E se quisermos tornar nossas animações ainda mais flexíveis, permitindo também efeitos de “deslizamento”, podemosbasta adicionar uma propriedade personalizada --kf-slide-to, semelhante ao que veremos na próxima seção. Quadros-chave de zoom bidirecional Outra animação comum que é duplicada em projetos são os efeitos de “zoom”. Quer seja um aumento sutil para mensagens de brinde, um zoom dramático para modais ou um efeito suave de redução para títulos, as animações de zoom estão em toda parte. Em vez de criar quadros-chave separados para cada valor de escala, vamos construir um conjunto flexível de quadros-chave kf-zoom:

/* * Zoom - animação em escala * Use --kf-zoom-from e --kf-zoom-to para controlar os valores da escala * Padrão: zoom de 80% a 100% (0,8 a 1) * Uso: * animação: kf-zoom 0,2s de atenuação; * --kf-zoom-de: 0,5; --kf-zoom-para: 1; //aumenta de 50% a 100% * --kf-zoom-de: 1; --kf-zoom-para: 0; //aumenta de 100% a 0% * --kf-zoom-de: 1; --kf-zoom-para: 1,1; //aumenta de 100% a 110% */

@quadros-chave kf-zoom { de { escala: var(--kf-zoom-from, 0,8); } para { escala: var(--kf-zoom-to, 1); } }

Com uma definição, podemos obter qualquer variação de zoom necessária: .brinde { animação: kf-deslizar 0,2s, kf-zoom 0,4s de atenuação; --kf-slide-from: 0 100%; /* desliza de cima para baixo */ /* Usa zoom padrão: escala de 80% a 100% */ }

.modal { animação: kf-zoom 0,3s cúbico-bezier (0,34, 1,56, 0,64, 1); --kf-zoom-de: 0; /* zoom dramático de 0% a 100% */ }

.cabeçalho { animação: kf-fade-in 2s, kf-zoom 2s facilidade; --kf-zoom-de: 1,2; --kf-zoom-para: 0,8; /* redução suave da escala */ }

O padrão de 0,8 (80%) funciona perfeitamente para a maioria dos elementos da interface do usuário, como mensagens de brinde e cartões, embora ainda seja fácil de personalizar para casos especiais. Veja os Pen Keyframes Tokens - Demo 4 [bifurcado] de Amit Sheen. Você deve ter notado algo interessante nos exemplos recentes: combinamos animações. Uma das principais vantagens de trabalhar com tokens @keyframes é que eles são projetados para se integrarem perfeitamente entre si. Esta composição suave é intencional, não acidental. Discutiremos a composição da animação com mais detalhes posteriormente, inclusive onde elas podem se tornar problemáticas, mas a maioria das combinações é direta e fácil de implementar. Nota: Enquanto escrevia este artigo, e talvez por causa dele, me peguei repensando toda a ideia de animações de entrada. Com todos os avanços recentes em CSS, ainda precisamos deles? Felizmente, Adam Argyle explorou as mesmas questões e as expressou de forma brilhante em seu blog. Isso não contradiz o que está escrito aqui, mas apresenta uma abordagem que vale a pena considerar, especialmente se seus projetos dependem muito de animações de entrada. Animações contínuas Enquanto as animações de entrada, como “fade”, “slide” e “zoom”, acontecem uma vez e depois param, as animações contínuas se repetem indefinidamente para chamar a atenção ou indicar atividade em andamento. As duas animações contínuas mais comuns que encontro são “spin” (para carregar indicadores) e “pulso” (para destacar elementos importantes). Essas animações apresentam desafios únicos quando se trata de criar tokens de quadros-chave. Ao contrário das animações de entrada que normalmente vão de um estado para outro, as animações contínuas precisam ser altamente personalizáveis ​​em seus padrões de comportamento. O Spin Doctor Cada projeto parece usar múltiplas animações de rotação. Alguns giram no sentido horário, outros no sentido anti-horário. Alguns fazem uma única rotação de 360 ​​graus, outros fazem várias voltas para um efeito mais rápido. Em vez de criar quadros-chave separados para cada variação, vamos construir um giro flexível que lide com todos os cenários:

/* * Spin - animação de rotação * Use --kf-spin-from e --kf-spin-to para controlar a faixa de rotação * Use --kf-spin-turns para controlar a quantidade de rotação * Padrão: gira de 0 graus a 360 graus (1 rotação completa) * Uso: * animação: kf-spin 1s linear infinito; * --kf-spin-turns: 2; // 2 rotações completas * --kf-spin-from: 0deg; --kf-spin-to: 180 graus; //meia rotação * --kf-spin-from: 0deg; --kf-spin-to: -360 graus; //sentido anti-horário */

@keyframes kf-spin { de { girar: var(--kf-spin-from, 0deg); } para { girar: calc(var(--kf-spin-from, 0deg) + var(--kf-spin-to, 360deg) * var(--kf-spin-turns, 1)); } }

Agora podemos criar qualquer variação de spin que desejarmos:

.carregando-spinner { animação: kf-spin 1s linear infinito; /* Usa o padrão: gira de 0 graus a 360 graus */ }

.carregador rápido { animação: kf-spin 1.2s alternativa infinita de facilidade de entrada; --kf-spin-turns: 3; /* 3 rotações completas para cada direção por ciclo*/ }

.passo reverso { animação: kf-spin 1.5s steps(8) infinito; --kf-spin-to: -360 graus; /* sentido anti-horário */ }

.subtle-wiggle { animação: alternativa infinita kf-spin 2s easy-in-out; --kf-spin-de: -16deg; --kf-spin-to: 32 graus; /* balança 36 graus: entre -18 graus e +18 graus */ }

Veja os Pen Keyframes Tokens - Demo 5 [bifurcado] de Amit Sheen. A beleza dessa abordagem é que os mesmos quadros-chave funcionam para carregar controles giratórios, girar ícones, efeitos de movimento e até mesmo animações complexas de múltiplas voltas. O paradoxo do pulso As animações de pulso são mais complicadas porque podem “pulsar” propriedades diferentes. Alguns pulsam a escala, outros pulsam a opacidade e alguns pulsam propriedades de cor, como brilho ou saturação. Em vez de criar quadros-chave separados para cada propriedade, podemos criar quadros-chave que funcionam com qualquer propriedade CSS. Aqui está um exemplo de quadro-chave de pulso com opções de escala e opacidade:

/* * Pulso - animação pulsante * Use --kf-pulse-scale-from e --kf-pulse-scale-to para controlar o intervalo da escala * Use --kf-pulse-opacity-from e --kf-pulse-opacity-to para controlar o intervalo de opacidade * Padrão: sem pulso (todos os valores 1) * Uso: * animação: alternativa infinita kf-pulse 2s easy-in-out; * --kf-escala de pulso-de: 0,95; --kf-escala de pulso para: 1,05; // escala pulso * --kf-pulso-opacidade-de: 0,7; --kf-pulso-opacidade-para: 1; // pulso de opacidade */

@keyframes kf-pulso { de { escala: var(--kf-escala de pulso-de, 1); opacidade: var(--kf-pulse-opacity-from, 1); } para { escala: var(--kf-escala de pulso-para, 1); opacidade: var(--kf-pulse-opacity-to, 1); } }

Isso cria um pulso flexível que pode animar diversas propriedades: .call to action { animação: kf-pulso 0,6s alternado infinito; --kf-pulso-opacidade-de: 0,5; /* pulso de opacidade */ }

.notificação-ponto { animação: kf-pulse 0,6s alternância infinita de facilidade de entrada; --kf-escala de pulso de: 0,9; --kf-escala de pulso para: 1,1; /* pulso de escala */ }

.text-destaque { animação: kf-pulse 1,5s atenuação infinita; --kf-escala de pulso de: 0,8; --kf-pulso-opacidade-de: 0,2; /* escala e pulso de opacidade */ }

Veja os Pen Keyframes Tokens - Demo 6 [bifurcado] de Amit Sheen. Este quadro-chave kf-pulse único pode lidar com tudo, desde capturas sutis de atenção até destaques dramáticos, ao mesmo tempo que é fácil de personalizar. Flexibilização Avançada Uma das melhores coisas sobre o uso de tokens de quadros-chave é como é fácil expandir nossa biblioteca de animação e fornecer efeitos que a maioria dos desenvolvedores não se preocuparia em escrever do zero, como elástico ou salto. Aqui está um exemplo de um token de quadro-chave de “salto” simples que usa uma propriedade personalizada --kf-bounce-from para controlar a altura do salto. /* * Bounce - animação de entrada saltitante * Use --kf-bounce-from para controlar a altura do salto * Padrão: salta de 100vh (fora da tela) * Uso: * animação: facilidade de entrada kf-bounce 3s; * --kf-bounce-from: 200px; // salta de 200px de altura */

@keyframes kf-bounce { 0% { traduzir: 0 calc(var(--kf-bounce-from, 100vh) * -1); }

34% { traduzir: 0 calc(var(--kf-bounce-from, 100vh) * -0,4); }

55% { traduzir: 0 calc(var(--kf-bounce-from, 100vh) * -0,2); }

72% { traduzir: 0 calc(var(--kf-bounce-from, 100vh) * -0,1); }

85% { traduzir: 0 calc(var(--kf-bounce-from, 100vh) * -0,05); }

94% { traduzir: 0 calc(var(--kf-bounce-from, 100vh) * -0,025); }

99% { traduzir: 0 calc(var(--kf-bounce-from, 100vh) * -0,0125); }

22%, 45%, 64%, 79%, 90%, 97%, 100% { traduzir: 0 0; função de temporização de animação: facilidade; } }

Animações como “elástica” são um pouco mais complicadas por causa dos cálculos dentro dos quadros-chave. Precisamos definir --kf-elastic-from-X e --kf-elastic-from-Y separadamente (ambos são opcionais), e juntos eles nos permitem criar uma entrada elástica a partir de qualquer ponto da tela.

/* * Elastic In - animação de entrada elástica * Use --kf-elastic-from-X e --kf-elastic-from-Y para controlar a posição inicial * Padrão: entra na parte superior central (0, -100vh) * Uso: * animação: kf-elastic-in 2s facilita a entrada e saída de ambos; * --kf-elástico-de-X: -50px; * --kf-elástico-de-Y: -200px; // insira de (-50px, -200px) */

@keyframes kf-elastic-in { 0% { traduzir: calc(var(--kf-elastic-from-X, -50vw) * 1) calc(var(--kf-elastic-from-Y, 0px) * 1); }

16% { traduzir: calc(var(--kf-elástico-de-X, -50vw) * -0,3227) calc(var(--kf-elástico-de-Y, 0px) * -0,3227); }

28% { traduzir: calc(var(--kf-elastic-from-X, -50vw) * 0,1312)calc(var(--kf-elástico-de-Y, 0px) * 0,1312); }

44% { traduzir: calc(var(--kf-elástico-de-X, -50vw) * -0,0463) calc(var(--kf-elástico-de-Y, 0px) * -0,0463); }

59% { traduzir: calc(var(--kf-elástico-de-X, -50vw) * 0,0164) calc(var(--kf-elástico-de-Y, 0px) * 0,0164); }

73% { traduzir: calc(var(--kf-elástico-de-X, -50vw) * -0,0058) calc(var(--kf-elástico-de-Y, 0px) * -0,0058); }

88% { traduzir: calc(var(--kf-elástico-de-X, -50vw) * 0,0020) calc(var(--kf-elástico-de-Y, 0px) * 0,0020); }

100% { traduzir: 0 0; } }

Essa abordagem facilita a reutilização e a personalização de quadros-chave avançados em nosso projeto, apenas alterando uma única propriedade personalizada.

.bounce-e-zoom { animação: kf-bounce 3s facilidade de entrada, kf-zoom 3s linear; --kf-zoom-de: 0; }

.saltar e deslizar { composição de animação: adicionar; /* Ambas as animações usam tradução */ animação: kf-bounce 3s facilidade de entrada, kf-slide-in 3s facilidade; --kf-slide-de: -200px; }

.elástico-in { animação: kf-elastic-in 2s facilita a entrada e saída de ambos; }

Veja os Pen Keyframes Tokens - Demo 7 [bifurcado] de Amit Sheen. Até agora, vimos como podemos consolidar quadros-chave de forma inteligente e eficiente. Claro, você pode querer ajustar as coisas para melhor atender às necessidades do seu projeto, mas cobrimos exemplos de várias animações comuns e casos de uso diários. E com esses tokens de quadros-chave implementados, agora temos blocos de construção poderosos para criar animações consistentes e sustentáveis ​​em todo o projeto. Chega de quadros-chave duplicados, chega de conflitos de escopo global. Apenas uma maneira limpa e conveniente de lidar com todas as nossas necessidades de animação. Mas a verdadeira questão é: como compomos esses blocos de construção juntos? Juntando tudo Vimos que combinar tokens de quadros-chave básicos é simples. Não precisamos de nada de especial a não ser definir a primeira animação, definir a segunda, definir as variáveis ​​conforme necessário e pronto. /* Fade in + slide in */ .brinde { animação: kf-fade-in 0,4s, kf-slide-in 0,4s cúbico-bézier (0,34, 1,56, 0,64, 1); --kf-slide-from: 0 40px; }

/* Zoom + fade in */ .modal { animação: kf-fade-in 0,3s, kf-zoom 0,3s cúbico-bézier (0,34, 1,56, 0,64, 1); --kf-zoom-de: 0,7; --kf-zoom-para: 1; }

/* Deslizar + pulsar */ .notificação { animação: kf-deslizar 0,5s, kf-pulse 1.2s alternância infinita de facilidade de entrada e saída; --kf-slide-from: -100px 0; --kf-escala de pulso-de: 0,95; --kf-escala de pulso para: 1,05; }

Essas combinações funcionam perfeitamente porque cada animação tem como alvo uma propriedade diferente: opacidade, transformação (tradução/escala), etc. Mas às vezes há conflitos e precisamos saber por que e como lidar com eles. Quando duas animações tentam animar a mesma propriedade — por exemplo, ambas animando escala ou ambas animando opacidade — o resultado não será o que você espera. Por padrão, apenas uma das animações é realmente aplicada a essa propriedade, que é a última na lista de animações. Esta é uma limitação de como o CSS lida com múltiplas animações na mesma propriedade. Por exemplo, isso não funcionará conforme o esperado porque apenas a animação kf-pulse será aplicada. .combo ruim { animação: kf-zoom 0,5s para frente, kf-pulso 1,2s alternado infinito; --kf-zoom-de: 0,5; --kf-zoom-para: 1,2; --kf-escala de pulso de: 0,8; --kf-escala de pulso para: 1,1; }

Adição de animação A maneira mais simples e direta de lidar com múltiplas animações que afetam a mesma propriedade é usar a propriedade Animation-Composition. No último exemplo acima, a animação kf-pulse substitui a animação kf-zoom, portanto não veremos o zoom inicial e não obteremos a escala esperada de 1,2. Ao definir a composição da animação a ser adicionada, informamos ao navegador para combinar as duas animações. Isso nos dá o resultado que desejamos. .componente-dois { composição de animação: adicionar; }

Veja os Pen Keyframes Tokens - Demo 8 [bifurcado] de Amit Sheen. Esta abordagem funciona bem na maioria dos casos em que queremos combinar efeitos na mesma propriedade. Também é útil quando precisamos combinar animações com valores de propriedades estáticas. Por exemplo, se tivermos um elemento que usa a propriedade translate para posicioná-lo exatamente onde queremos, e então quisermos animá-lo com os quadros-chave kf-slide-in, obteremos um salto visível desagradável sem composição de animação. Veja os Pen Keyframes Tokens - Demo 9 [bifurcado] de Amit Sheen. Com a composição de animação definida para adicionar, a animação é combinada suavemente com o existentetransformar, para que o elemento permaneça no lugar e seja animado conforme o esperado. Escalonamento de animação Outra maneira de lidar com múltiplas animações é “escaloná-las” – ou seja, iniciar a segunda animação um pouco depois que a primeira terminar. Não é uma solução que funcione para todos os casos, mas é útil quando temos uma animação de entrada seguida de uma animação contínua. /* fade in + pulso de opacidade */ .notificação { animação: kf-fade-in 2s suavização, kf-pulso 0,5s 2s alternância infinita de entrada e saída; --kf-pulso-opacidade-para: 0,5; }

Veja os Pen Keyframes Tokens - Demo 10 [bifurcado] de Amit Sheen. Pedidos são importantes Grande parte das animações com as quais trabalhamos utilizam a propriedade transform. Na maioria dos casos, isto é simplesmente mais conveniente. Ele também tem uma vantagem de desempenho, pois as animações de transformação podem ser aceleradas por GPU. Mas se usarmos transformações, precisamos aceitar que a ordem em que realizamos as nossas transformações é importante. Bastante. Até agora, em nossos quadros-chave, usamos transformações individuais. De acordo com as especificações, elas são sempre aplicadas em uma ordem fixa: primeiro, o elemento é transladado, depois girado e depois dimensionado. Isso faz sentido e é o que a maioria de nós espera. Porém, se usarmos a propriedade transform, a ordem em que as funções são escritas é a ordem em que são aplicadas. Neste caso, se movermos algo 100 pixels no eixo X e depois girarmos 45 graus, não é o mesmo que primeiro girá-lo 45 graus e depois movê-lo 100 pixels. /* Quadrado rosa: primeiro traduza e depois gire */ .exemplo-um { transformar: traduzirX(100px) girar(45deg); }

/* Quadrado verde: primeiro gire e depois transfira */ .exemplo-dois { transformar: girar (45 graus) traduzirX (100px); }

Veja os Pen Keyframes Tokens - Demo 11 [bifurcado] de Amit Sheen. Mas de acordo com a ordem de transformação, todas as transformações individuais — tudo o que usamos para os tokens de quadros-chave — acontecem antes das funções de transformação. Isso significa que tudo o que você definir na propriedade transform acontecerá após as animações. Mas se você definir, por exemplo, a tradução junto com os quadros-chave kf-spin, a tradução acontecerá antes da animação. Ainda confuso?! Isto leva a situações onde valores estáticos podem causar resultados diferentes para a mesma animação, como no caso a seguir:

/* Animação comum para ambos os spinners */ .spinner { animação: kf-spin 1s linear infinito; }

/* Spinner rosa: traduz antes de girar (transformação individual) */ .spinner-rosa { traduzir: 100% 50%; }

/* Spinner verde: gire e depois traduza (ordem da função) */ .spinner-verde { transformar: traduzir(100%, 50%); }

Veja os Pen Keyframes Tokens - Demo 12 [bifurcado] de Amit Sheen. Você pode ver que o primeiro botão giratório (rosa) recebe uma translação que acontece antes da rotação do kf-spin, então ele primeiro se move para seu lugar e depois gira. O segundo controle giratório (verde) recebe uma função translate() que acontece após a transformação individual, de modo que o elemento primeiro gira e depois se move em relação ao seu ângulo atual, e obtemos aquele efeito de órbita ampla. Não, isso não é um bug. É apenas uma daquelas coisas que precisamos saber sobre CSS e ter em mente ao trabalhar com múltiplas animações ou múltiplas transformações. Se necessário, você também pode criar um conjunto adicional de quadros-chave kf-spin-alt que giram elementos usando a função rotate(). Movimento Reduzido E enquanto falamos de quadros-chave alternativos, não podemos ignorar a opção “sem animação”. Uma das maiores vantagens de usar tokens de quadros-chave é que a acessibilidade pode ser integrada e, na verdade, é muito fácil de fazer. Ao projetar nossos quadros-chave tendo em mente a acessibilidade, podemos garantir que os usuários que preferem movimentos reduzidos obtenham uma experiência mais suave e menos perturbadora, sem trabalho extra ou duplicação de código. O significado exato de “Movimento Reduzido” pode mudar um pouco de uma animação para outra e de projeto para projeto, mas aqui estão alguns pontos importantes a serem considerados: Silenciando quadros-chave Embora algumas animações possam ser suavizadas ou desaceleradas, há outras que devem desaparecer completamente quando o movimento reduzido é solicitado. As animações de pulso são um bom exemplo. Para garantir que essas animações não sejam executadas no modo de movimento reduzido, podemos simplesmente envolvê-las na consulta de mídia apropriada.

@media (prefere movimento reduzido: sem preferência) { @keyfrmaes kf-pulso { de { escala: var(--kf-escala de pulso-de, 1); opacidade: var(--kf-pulse-opacity-from, 1); } para { escala: var(--kf-escala de pulso-para, 1); opacidade:var(--kf-pulso-opacidade-para, 1); } } }

Isso garante que os usuários que definiram o movimento preferencial como reduzido não verão a animação e obterão uma experiência que corresponda às suas preferências. Entrada instantânea Existem alguns quadros-chave que não podemos simplesmente remover, como animações de entrada. O valor deve mudar, deve ser animado; caso contrário, o elemento não terá os valores corretos. Mas em movimento reduzido, esta transição do valor inicial deve ser instantânea. Para conseguir isso, definiremos um conjunto extra de quadros-chave onde o valor salta imediatamente para o estado final. Estes se tornam nossos quadros-chave padrão. Em seguida, adicionaremos os quadros-chave regulares dentro de uma consulta de mídia para preferências de movimento reduzido definidas como sem preferência, assim como no exemplo anterior. /* aparece instantaneamente para reduzir o movimento */ @quadros-chave kf-zoom { de, para { escala: var(--kf-zoom-to, 1); } }

@media (prefere movimento reduzido: sem preferência) { /* Quadros-chave de zoom originais */ @quadros-chave kf-zoom { de { escala: var(--kf-zoom-from, 0,8); } para { escala: var(--kf-zoom-to, 1); } } }

Dessa forma, os usuários que preferem movimento reduzido verão o elemento aparecer instantaneamente em seu estado final, enquanto todos os demais obtêm a transição animada. A abordagem suave Há casos em que queremos sim manter algum movimento, mas muito mais suave e calmo que a animação original. Por exemplo, podemos substituir uma entrada rebatida por um fade-in suave.

@keyframes kf-bounce { /* Fade-in suave para movimento reduzido */ }

@media (prefere movimento reduzido: sem preferência) { @keyframes kf-bounce { /* Quadros-chave de rejeição originais */ } }

Agora, os usuários com movimento reduzido habilitado ainda têm uma sensação de aparência, mas sem o movimento intenso de um salto ou animação elástica. Com os blocos de construção implementados, a próxima questão é como torná-los parte do fluxo de trabalho real. Escrever quadros-chave flexíveis é uma coisa, mas torná-los confiáveis ​​em um projeto grande requer algumas estratégias que tive que aprender da maneira mais difícil. Estratégias de implementação e melhores práticas Assim que tivermos uma biblioteca sólida de tokens de quadros-chave, o verdadeiro desafio é como trazê-los para o trabalho diário.

A tentação é incluir todos os quadros-chave de uma vez e declarar o problema resolvido, mas na prática descobri que os melhores resultados vêm da adoção gradual. Comece com as animações mais comuns, como fade ou slide. São vitórias fáceis que mostram valor imediato sem exigir grandes reescritas. A nomenclatura é outro ponto que merece atenção. Um prefixo ou namespace consistente torna óbvio quais animações são tokens e quais são pontuais locais. Também evita colisões acidentais e ajuda os novos membros da equipe a reconhecer rapidamente o sistema compartilhado. A documentação é tão importante quanto o próprio código. Mesmo um breve comentário acima de cada token de quadro-chave pode economizar horas de adivinhação mais tarde. Um desenvolvedor deve ser capaz de abrir o arquivo de tokens, procurar o efeito necessário e copiar o padrão de uso diretamente em seu componente. Flexibilidade é o que faz com que essa abordagem valha o esforço. Ao expor propriedades personalizadas sensíveis, damos às equipes espaço para adaptar a animação sem quebrar o sistema. Ao mesmo tempo, tente não complicar demais. Forneça os botões que importam e mantenha o resto opinativo. Finalmente, lembre-se da acessibilidade. Nem toda animação precisa de uma alternativa de movimento reduzido, mas muitas precisam. Fazer esses ajustes antecipadamente significa que nunca teremos que adaptá-los mais tarde e mostra um nível de cuidado que nossos usuários perceberão, mesmo que nunca mencionem isso.

Na minha experiência, tratar tokens de quadros-chave como parte de nosso fluxo de trabalho de tokens de design é o que os faz permanecer. Uma vez instalados, eles deixam de parecer efeitos especiais e passam a fazer parte da linguagem do design, uma extensão natural de como o produto se move e responde. Concluindo As animações podem ser uma das partes mais alegres da construção de interfaces, mas sem estrutura, também podem se tornar uma das maiores fontes de frustração. Ao tratar os quadros-chave como tokens, você pega algo que geralmente é confuso e difícil de gerenciar e o transforma em um sistema claro e previsível. O valor real não está apenas em salvar algumas linhas de código. É a certeza de que, ao usar fade, slide, zoom ou spin, você sabe exatamente como ele se comportará em todo o projeto. Está na flexibilidade que advém das propriedades personalizadas, sem o caos de variações infinitas. E está na acessibilidade incorporada na fundação, em vez de adicionada comouma reflexão tardia. Já vi essas ideias funcionarem em equipes e bases de código diferentes, e o padrão é sempre o mesmo. Uma vez que os tokens estejam no lugar, os quadros-chave deixam de ser uma coleção dispersa de truques e passam a fazer parte da linguagem de design. Eles fazem o produto parecer mais intencional, mais consistente e mais vivo. Se você tirar algo deste artigo, que seja o seguinte: as animações merecem o mesmo cuidado e estrutura que já damos às cores, tipografia e espaçamento. Um pequeno investimento em tokens de quadros-chave compensa sempre que sua interface se move.

You May Also Like

Enjoyed This Article?

Get weekly tips on growing your audience and monetizing your content — straight to your inbox.

No spam. Join 138,000+ creators. Unsubscribe anytime.

Create Your Free Bio Page

Join 138,000+ creators on Seemless.

Get Started Free