Easing baseado em física

Recursos da Web: suavização linear()

As funções de easing tradicionais do CSS, como ease-in ou cubic-bezier(), são limitadas a curvas simples, o que impossibilita a criação de efeitos complexos baseados em física, como saltos ou molas. A função de tempo linear() resolve isso permitindo que você forneça uma série de paradas que podem se aproximar de curvas complexas. As transições e animações são interpoladas com base em linhas retas entre as paradas, mas, com paradas suficientes, elas podem parecer suaves.

Etapas de implementação

  1. Gerar os pontos da curva: traçar manualmente dezenas de pontos para uma mola ou um salto não é prático. Use uma função de tempo de uma biblioteca externa ou uma ferramenta para converter uma função de easing do JavaScript ou um caminho SVG na sintaxe linear(). Opcional: armazene essas funções de tempo como propriedades personalizadas de CSS para reutilização em todo o site.
  2. Defina a função de tempo: aplique as paradas geradas à propriedade transition-timing-function ou animation-timing-function ou use as abreviações transition ou animation.
  3. Ajuste a duração: ao contrário dos mecanismos de física do JavaScript, em que a duração é derivada de propriedades físicas (massa, rigidez), o CSS ainda requer uma duration fixa. Talvez seja necessário ajustar a duração para conseguir o efeito desejado.

Exemplo: Spring Easing

Este exemplo mostra como usar uma função linear() personalizada para criar um efeito de mola que ultrapassa o valor de destino antes de se estabilizar.

.spring {
  /* Define the physics-based easing as a reusable variable */
  --spring-easing: linear(0, 0.016 0.5%, 0.06 1%, 0.226 2%, 1.116 5.4%, 1.375 6.6%, 1.527 7.7%, 1.565 8.2%, 1.585 8.8%, 1.581 9.3%, 1.559 9.8%, 1.458 10.9%, 0.937 14.3%, 0.784 15.5%, 0.693 16.6%, 0.67 17.1%, 0.657 17.7%, 0.671 18.7%, 0.729 19.8%, 1.042 23.3%, 1.13 24.5%, 1.182 25.6%, 1.201 26.7%, 1.192 27.7%, 1.156 28.8%, 0.977 32.2%, 0.925 33.4%, 0.894 34.5%, 0.882 35.6%, 0.887 36.6%, 0.907 37.7%, 1.045 42.4%, 1.069 44.5%, 1.059 46.3%, 0.979 50.9%, 0.96 53.4%, 0.966 55.3%, 1.013 59.9%, 1.024 62.3%, 0.986 71.2%, 1.008 79.9%, 0.995 88.9%, 1);


  /* Apply the easing with a duration that fits the spring's complexity */
  /* MANDATORY: Always include a duration; linear() does not calculate it automatically */
  transition: scale 0.8s var(--spring-easing);
}

.spring:hover {
  scale: 1.2;
}

Exemplo: Bounce Easing

Este exemplo mostra como usar uma função linear() personalizada para criar um efeito de salto.

.bounce {
  /* Define the physics-based easing as a reusable variable */
  --bounce-easing: linear(0, 0.214 14.7%, 0.386 23.7%, 0.598 31.9%, 0.999 44.7%, 0.807 52.6%, 0.762 56%, 0.747 59.4%, 0.758 62.4%, 0.793 65.6%, 0.999 77.4%, 0.961 81.2%, 0.949 84.8%, 0.956 88%, 0.993 95.5%, 1);


  /* Apply the easing with a duration that fits the bounce's complexity */
  /* MANDATORY: Always include a duration; linear() does not calculate it automatically */
  transition: scale 0.4s var(--bounce-easing);
}

.bounce:hover {
  scale: 1.2;
}

Principais Considerações

  • Desempenho: para as animações baseadas em física mais suaves, aplique linear() a propriedades executadas em uma linha de execução separada, como transform e opacity.
  • Precisão x payload: embora mais paradas resultem em uma curva mais suave, elas também aumentam o tamanho do CSS. A maioria dos geradores permite "simplificar" a curva para encontrar o equilíbrio ideal entre suavidade e tamanho do código.
  • Evite a opacidade para saltos: aplicar suavizações de salto a opacity pode causar uma oscilação visualmente desagradável se o valor ultrapassar 0 ou 1.
  • Acessibilidade: animações complexas baseadas em física podem distrair ou causar sensibilidade ao movimento em alguns usuários. Sempre respeite as preferências do usuário reduzindo ou desativando essas animações.
@media (prefers-reduced-motion: reduce) {
  .element {
    transition: none;
  }
}

Estratégias de fallback

CSS substituto

Para navegadores que não oferecem suporte a linear(), forneça uma função de easing padrão como substituta. O navegador vai ignorar o valor linear() se não o reconhecer, voltando para a declaração válida anterior.

.element {
  /* Fallback for older browsers (standard smooth exit) */
  transition: transform 0.8s ease-out;
  
  /* Modern browsers will override with the physics-based easing */
  transition-timing-function: linear(0, 1.1, 0.95, 1.02, 1);
}

Fallback da biblioteca JavaScript (Motion/GSAP)

Opcional: se uma animação física de alta fidelidade for essencial mesmo em navegadores mais antigos, use uma biblioteca JavaScript como Motion (motion.dev) ou GSAP (greensock.com) para processar a animação quando linear() não for compatível.

  1. Detectar suporte: use CSS.supports() para verificar se o navegador processa a função linear().
  2. Carregar/aplicar condicionalmente: se não houver suporte, use a implementação de mola ou de retorno da biblioteca.
/* Detect if the browser supports the linear() function */
const supportsLinearEasing = window.CSS && CSS.supports('animation-timing-function', 'linear(0, 1)');

if (!supportsLinearEasing) {
  /* 
     Example using Motion (motion.dev) for a spring fallback.
     This should only be initialized if native CSS support is missing.
  */
  import("https://cdn.jsdelivr.net/npm/motion@latest/dist/motion.js").then(({ animate, spring }) => {
    animate(".element", { transform: "scale(1.2)" }, {
      easing: spring({ stiffness: 100, damping: 10 })
    });
  });
}

Você também pode usar @supports em CSS para uma detecção de recursos mais explícita:

@supports not (animation-timing-function: linear(0, 1)) {
  .element {
    /* Alternative experience for unsupported browsers */
    transition-duration: 0.4s;
    transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
  }
}