Controle mais refinado sobre transformações CSS com propriedades de transformação individuais

Transformar elementos com as propriedades translate, rotate e scale

A propriedade transform do CSS

Para aplicar transformações a um elemento, use a propriedade transform do CSS. A propriedade aceita um ou mais <transform-function>s que são aplicados um após o outro.

.target {
  transform: translateX(50%) rotate(30deg) scale(1.2);
}

O elemento de destino é traduzido em 50% no eixo X, girado em 30 graus e, por fim, dimensionado para 120%.

Embora a propriedade transform funcione bem, pode ser um pouco tedioso mudar qualquer um desses valores individualmente.

Para mudar a escala ao passar o cursor, duplique todas as funções na propriedade de transformação, mesmo que os valores não sejam alterados.

.target:hover {
  transform: translateX(50%) rotate(30deg) scale(2); /* Only the value of scale() changed */
}

As propriedades de transformação individuais

O Chrome 104 inclui propriedades individuais para transformações CSS. As propriedades são scale, rotate e translate, que podem ser usadas para definir individualmente essas partes de uma transformação.

Com isso, o Chrome se junta ao Firefox e ao Safari, que já são compatíveis com essas propriedades.

Compatibilidade com navegadores

  • Chrome: 104.
  • Edge: 104.
  • Firefox: 72.
  • Safari: 14.1.

Origem

Reescreva o exemplo transform anterior com as propriedades individuais. Seu snippet vai ficar assim:

.target {
  translate: 50% 0;
  rotate: 30deg;
  scale: 1.2;
}

A ordem é importante

Uma diferença importante entre a propriedade transform original do CSS e as novas propriedades é a ordem em que as transformações declaradas são aplicadas.

Com transform, as funções de transformação são aplicadas na ordem em que são gravadas, da esquerda (de fora) para a direita (para dentro).

Com as propriedades de transformação individuais, a ordem não é a ordem em que são declaradas. A ordem é sempre a mesma: primeiro translate (externo), depois rotate e, por fim, scale (interno).

Isso significa que os dois snippets de código a seguir têm o mesmo resultado:

.transform--individual {
  translate: 50% 0;
  rotate: 30deg;
  scale: 1.2;
}

.transform--individual-alt {
  rotate: 30deg;
  translate: 50% 0;
  scale: 1.2;
}

Em ambos os casos, os elementos de destino são primeiro movidos por 50% no eixo X, depois girados por 30deg e, por fim, dimensionados por 1.2.

Se uma das propriedades de transformação individuais for declarada junto com uma propriedade transform, as transformações individuais serão aplicadas primeiro (translate, rotate e depois scale) com transform por último (dentro). Mais detalhes estão na especificação que define como a matriz de transformação deve ser calculada.

Animações

O principal motivo para adicionar essas propriedades foi facilitar as animações. Digamos que você queira animar um elemento da seguinte maneira:

Gráfico de frames-chave.

Como usar o transform

Para implementar essa animação usando transform, você precisa calcular todos os valores intermediários para todas as transformações definidas e incluí-los em cada frame-chave. Por exemplo, para fazer uma rotação na marca de 10%, os valores das outras transformações também precisam ser calculados, porque a propriedade transform precisa de todos eles.

Gráfico de frames-chave com valores intermediários calculados.

O código CSS resultante fica assim:

@keyframes anim {
  0% { transform: translateX(0%); }
  5% { transform: translateX(5%) rotate(90deg) scale(1.2); }
  10% { transform: translateX(10%) rotate(180deg) scale(1.2); }
  90% { transform: translateX(90%) rotate(180deg) scale(1.2); }
  95% { transform: translateX(95%) rotate(270deg) scale(1.2); }
  100% { transform: translateX(100%) rotate(360deg); }
}

.target {
  animation: anim 2s;
  animation-fill-mode: forwards;
}

Como usar propriedades de transformação individuais

Com propriedades de transformação individuais, isso se torna muito mais fácil de escrever. Em vez de arrastar todas as transformações de frame-chave para frame-chave, você pode segmentar cada transformação individualmente. Você também não precisa mais calcular todos os valores intermediários.

@keyframes anim {
  0% { translate: 0% 0; }
  100% { translate: 100% 0; }

  0%, 100% { scale: 1; }
  5%, 95% { scale: 1.2; }

  0% { rotate: 0deg; }
  10%, 90% { rotate: 180deg; }
  100% { rotate: 360deg; }
}

.target {
  animation: anim 2s;
  animation-fill-mode: forwards;
}

Como usar propriedades de transformação individuais e vários frames-chave

Para tornar o código modular, divida cada subanimação em um conjunto de frames-chave.

@keyframes move {
  0% { translate: 0% 0; }
  100% { translate: 100% 0; }
}

@keyframes scale {
  0%, 100% { scale: 1; }
  5%, 95% { scale: 1.2; }
}

@keyframes rotate {
  0% { rotate: 0deg; }
  10%, 90% { rotate: 180deg; }
  100% { rotate: 360deg; }
}

.target {
  animation: move 2s, scale 2s, rotate 2s;
  animation-fill-mode: forwards;
}

Graças a essa divisão, você pode aplicar cada conjunto de keyframes separadamente, porque as propriedades transform, que agora se tornaram individuais, não se sobrescrevem mais. Além disso, é possível definir um tempo diferente para cada transformação sem precisar reescrever o lote inteiro.

Desempenho

As animações que usam essas novas propriedades são tão eficientes quanto as animações da propriedade transform.

As animações de translate, rotate e scale são executadas no compositor da mesma forma que as animações de transform. Por isso, elas são boas para o desempenho de animação da mesma forma que transform.

Essas novas propriedades também funcionam com a propriedade will-change. Em geral, é melhor evitar o uso excessivo de will-change. Use o mínimo de elementos necessários e pelo menor tempo possível. No entanto, também é bom ser o mais específico possível. Por exemplo, se você estiver usando will-change para otimizar uma animação com as propriedades rotate e filter, declare isso usando will-change: rotate, filter. Isso é um pouco melhor do que usar will-change: transform, filter em um caso em que você está animando rotate e filter, porque algumas das estruturas de dados que o Chrome cria com antecedência quando você usa will-change são diferentes para transform em comparação com rotate.

Parte da série "Novos recursos de interoperabilidade"