Curso de CSS / Transformações e transições

Transformações movem, giram ou redimensionam a aparência renderizada de uma caixa sem reordenar o conteúdo ao redor. Transições animam uma mudança entre valores de propriedade, então selecione as propriedades e o tempo deliberadamente e forneça uma alternativa para movimento reduzido.

Entenda transformações e fluxo normal

O fluxo de documentos refere-se à relação entre onde um elemento é colocado originalmente e os elementos ao redor. Mesmo que você mova o botão para cima até translateY(-.5rem), o parágrafo abaixo não se move de acordo com o espaço para onde o botão foi movido. Elementos transformados podem se sobrepor ao conteúdo ao redor ou sair da tela, portanto, deixar espaço suficiente em sua colocação original é uma prioridade em vez de aumentar a distância do movimento.

função Exemplo Resultados a Observar
translate() translate(1rem, -.5rem) Mover 1rem para a direita, 0,5rem para cima
rotate() rotate(15deg) Rotacionar em torno de um ponto de referência
scale() scale(1.05) Exibido a 1,05 vezes o tamanho original

Só porque o tamanho parece maior não significa que o espaço ocupado pela caixa antes da conversão será maior. Use Grid ou width para mudar o espaço real do cartão no layout; use transform para um efeito visual de ampliação sem reorganizar os vizinhos. Caixas inline que não são substituídas, como texto simples span, não são convertidas, portanto, especifique display: inline-block, se necessário. Definições de alvos de transformação e processamento de coordenadas podem ser encontradas no documento de transformação MDN.

Compare a ordem da transformação e a origem

Quando você lista funções de transformação, cada função afeta o sistema de coordenadas usado pela próxima função. Portanto, translação/rotação e rotação/translação geralmente não produzem o mesmo resultado. No exemplo abaixo, a caixa rotacionada de A é visível onde foi movida para a direita, e a caixa de B se moveu na direção afetada pela rotação e é visível mais abaixo. Não basta olhar o nome da função e assumir que os dois resultados são iguais; compare suas localizações reais. Com raiz de 16px e origem central, A desloca o centro 32px para a direita; B desloca aproximadamente 22,63px para a direita e 22,63px para baixo. A lista altera os sistemas de coordenadas da esquerda para a direita; ao compor matrizes sobre um ponto fixo, a matriz mais à direita atua primeiro.

O ponto de origem da rotação e do redimensionamento é definido por transform-origin. Se você usar left top em vez do centro padrão, ele irá girar em torno do canto superior esquerdo. Isso é útil quando você quer fixar um ponto específico, como quando um menu se abre, mas a sobreposição com o conteúdo ao redor pode mudar apenas alterando o ponto de referência.

Salve o código a seguir como transform-compare.html em UTF-8 e abra-o em seu navegador. Nenhum arquivo ou biblioteca externa é necessário.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Transform order and origin</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; }
.comparisons { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); gap: 1rem; }
.slot { padding: 1rem; border: 1px solid #8a9ba7; }
.frame { height: 9rem; display: grid; place-items: center; background: #f0f2f4; }
.box { width: 4rem; height: 2rem; display: grid; place-items: center; background: #166b92; color: white; }
.first { transform: translateX(2rem) rotate(45deg); }
.second { transform: rotate(45deg) translateX(2rem); }
.center { transform: rotate(30deg); transform-origin: center; }
.corner { transform: rotate(30deg); transform-origin: left top; }
  </style>
</head>
<body>
<main>
<h1>The same value also varies depending on the order and reference point</h1>
<div class="comparisons">
  <section class="slot"><h2>Translate, then rotate</h2><div class="frame"><div class="box first">A</div></div></section>
  <section class="slot"><h2>Rotate, then translate</h2><div class="frame"><div class="box second">B</div></div></section>
  <section class="slot"><h2>Center origin</h2><div class="frame"><div class="box center">C</div></div></section>
  <section class="slot"><h2>Top-left origin</h2><div class="frame"><div class="box corner">D</div></div></section>
</div>
</main>
</body>
</html>
  1. Compare as posições de A e B. Se você alterar a ordem das funções de .second para ser a mesma que a de A, as posições relativas das duas caixas serão as mesmas. Após a confirmação, retorne para a ordem original.
  2. C e D têm o mesmo ângulo de rotação. Altere apenas o transform-origin de .corner para center, verifique a diferença nos pontos de referência e restaure para left top.
  3. Compare a ampliação alterando apenas a rotação de C para scale(1.2). A área fora da caixa irá crescer, mas a área ao redor não será realocada. Após a confirmação, restaure para rotate(30deg).

Escolha as propriedades de transição e o tempo

transition não muda de estado por si só. A mudança começa apenas quando o valor de CSS muda em hover, focus ou alteração de classe. Especifique o nome da propriedade a ser afetada, duração, curva de progressão e atraso de início; se o atraso for omitido, o padrão é 0 segundos.

transition: transform 180ms ease 0ms, background-color 180ms ease 0ms;

Aqui, 180ms é 0,18 segundos, e ease é uma curva que conecta suavemente o início e o fim, em vez de prosseguir apenas na mesma velocidade. linear muda em uma taxa constante. Use tempos curtos e sem atrasos primeiro, depois ajuste conforme necessário. Adicionar um longo atraso a um botão aparentemente sem resposta pode dificultar a percepção dos resultados das suas ações.

Colocar transition na regra base permite que ele opere tanto na entrada quanto no retorno. Uma transição declarada apenas em :hover desaparece quando o hover termina e pode produzir um retorno diferente. Nomeie as propriedades deliberadamente em vez de usar all. Este exemplo transita transform e background-color; nem toda propriedade interpola da mesma maneira. Para mais detalhes, veja o documento MDN sobre transições.

Teste hover e foco do teclado

Salve o código abaixo como transition-state.html. Quando você passar o mouse sobre o botão ou usar a tecla Tab, o botão se move para cima e a cor de fundo muda. Os pontos de foco são destacados individualmente em azul escuro. O botão é apenas para fins de prática, para observar as mudanças de estado, e nenhuma ação adicional é executada após pressionar o botão.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Transforms and state transitions 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; }
.stage { padding: 2rem 1rem; border: 2px dashed #8a9ba7; }
.action { padding: .75rem 1.25rem; border: 1px solid #166b92; border-radius: .4rem;
  color: #183044; background: #eaf4fa; transform: translateY(0);
  transition: transform 180ms ease, background-color 180ms ease; }
.action:hover, .action:focus-visible { transform: translateY(-.5rem); background: #cfe8f4; }
.neighbor { margin-block: 1rem 0; padding: .75rem; background: #f0f2f4; }
@media (prefers-reduced-motion: reduce) {
  .action { transition: none; }
  .action:hover, .action:focus-visible { transform: none; }
}
  </style>
</head>
<body>
<main>
<h1>The paragraph stays in place as the button moves</h1>
<p>Hover over the button or press Tab to focus it.</p>
<div class="stage">
  <button class="action" type="button">Check state</button>
  <p class="neighbor">This paragraph stays in place when the button is transformed.</p>
</div>
</main>
</body>
</html>
  1. Lembre-se da posição superior do parágrafo abaixo e passe o mouse sobre o botão. Apenas os botões se movem e os parágrafos devem permanecer no mesmo lugar.
  2. Altere a duração em dois lugares de 180ms para 800ms para observar a entrada e o retorno, depois retorne ao valor original.
  3. Deixe o tempo como está e mude apenas a curva de progresso para linear para comparação. Em seguida, restaure para ease.
  4. Adicionamos apenas um atraso 400ms ao final da primeira transição. Como a primeira transição corresponde a transform, o movimento espera 400ms; a transição da cor de fundo começa imediatamente. Depois remova o atraso.
  5. Foque no botão com a tecla Tab e saia com Shift+Tab. Certifique-se de que o contorno de foco e a cor de fundo descrevam o estado de operação.

Reduza o movimento e verifique efeitos colaterais

Se o usuário configurou para reduzir o movimento, as regras dentro de prefers-reduced-motion: reduce eliminarão o movimento neste exemplo, deixando apenas a cor de fundo e os marcadores de foco. Se você apenas remover a transição, a mudança ocorrerá imediatamente, mas a posição final para a qual você se moveu permanecerá. No exemplo acima, decidimos que o próprio movimento decorativo era desnecessário, então até mesmo as transformações de hover e foco foram alterados para none. Por favor, consulte o guia de configuração de redução de movimento MDN.

Compare os dois estados alterando as configurações do seu sistema operacional ou reproduzindo as características da mídia no painel de Renderização das ferramentas de desenvolvimento do seu navegador. Na configuração reduzida, o botão não deve se mover, apenas a cor e o indicador de foco devem mudar. Quando terminar o laboratório, restaure a emulação para seu estado padrão.

Um transform que não seja 'none' cria um contexto de empilhamento e pode estabelecer o bloco contêiner para descendentes absolutos e fixos. Se um popup ou elemento fixo se comportar de maneira inesperada, inspecione ancestrais transformados. Verifique também sobreposição, foco do teclado e movimento reduzido; uma transição suave por si só não estabelece um layout utilizável. Veja position: relative, absolute, fixed e sticky, z-index e contextos de empilhamento.