View Transitions API: animações de página nativas sem biblioteca
1. Introdução à View Transitions API
A View Transitions API é uma especificação nativa do navegador que permite criar animações suaves entre estados de uma página — seja durante navegações entre rotas em Single Page Applications (SPA) ou entre páginas completas em Multi-Page Applications (MPA). Diferente de bibliotecas como GSAP, Framer Motion ou soluções baseadas em React Transition Group, essa API opera diretamente no motor de renderização do navegador, eliminando a necessidade de carregar kilobytes de JavaScript apenas para efeitos visuais.
O principal problema resolvido é a complexidade de implementar transições fluidas entre páginas sem perder performance. Tradicionalmente, desenvolvedores precisavam gerenciar manualmente o ciclo de vida de animações, estados de carregamento e sincronização com dados assíncronos. A View Transitions API abstrai todo esse processo, capturando automaticamente o estado visual antes e depois da mudança.
2. Como funciona o mecanismo de transição
O coração da API é o conceito de "snapshot" — uma captura instantânea da tela atual. Quando uma transição é iniciada, o navegador:
- Tira um screenshot da página atual (estado "old")
- Aplica as mudanças no DOM (nova rota, novos dados)
- Tira um screenshot do novo estado (estado "new")
- Interpola entre os dois usando animações CSS padrão
Esses snapshots são representados por pseudo-elementos especiais na árvore de transição:
::view-transition
└── ::view-transition-group(root)
├── ::view-transition-image-pair(root)
│ ├── ::view-transition-old(root)
│ └── ::view-transition-new(root)
O ciclo de vida é controlado pelo método document.startViewTransition(callback), que retorna uma promessa. Se a API não for suportada, o callback é executado normalmente sem animação — garantindo fallback automático.
3. Configuração básica: transições entre páginas SPA
Em aplicações SPA, a implementação mínima envolve envolver a lógica de navegação com startViewTransition. Exemplo com React Router:
import { useNavigate } from 'react-router-dom';
function navigateWithTransition(to) {
if (document.startViewTransition) {
document.startViewTransition(() => {
// React Router atualizará o DOM dentro deste callback
navigate(to);
});
} else {
navigate(to);
}
}
Para frameworks reativos como Svelte ou Astro, o princípio é o mesmo — qualquer mudança que altere o DOM pode ser encapsulada:
// Exemplo com Svelte
async function handleNavigation(event) {
event.preventDefault();
const url = event.target.href;
if (document.startViewTransition) {
await document.startViewTransition(async () => {
await navigate(url); // função que atualiza o estado da rota
}).finished;
} else {
await navigate(url);
}
}
4. Transições entre páginas MPA (Multi-Page Application)
Para sites tradicionais com navegação completa entre páginas HTML, a ativação é ainda mais simples — basta adicionar uma meta tag no <head>:
<meta name="view-transition" content="same-origin">
Isso habilita transições automáticas entre páginas do mesmo domínio. O navegador gerencia todo o processo: captura a página atual, carrega a nova URL e anima a transição. A limitação principal é a falta de controle granular — você não pode personalizar animações por elemento ou sincronizar com dados carregados via AJAX.
5. Personalização de animações com CSS
As animações padrão (fade crossfade) podem ser substituídas por @keyframes customizados. Os seletores específicos permitem controle preciso:
/* Animação de slide horizontal */
@keyframes slide-from-right {
from { transform: translateX(100%); }
to { transform: translateX(0); }
}
@keyframes slide-to-left {
from { transform: translateX(0); }
to { transform: translateX(-100%); }
}
::view-transition-old(root) {
animation: 300ms ease-in slide-to-left;
}
::view-transition-new(root) {
animation: 300ms ease-out slide-from-right;
}
Para fade-in/fade-out personalizado:
@keyframes fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
::view-transition-old(root) {
animation: 200ms ease-out fade-out;
}
::view-transition-new(root) {
animation: 200ms ease-in fade-in;
}
6. Transições de elementos compartilhados (cross-fade)
Um dos recursos mais poderosos é a capacidade de animar elementos específicos que mudam de posição, tamanho ou forma entre estados. Basta atribuir um view-transition-name único no CSS:
/* Card que aparece em duas páginas diferentes */
.card-destaque {
view-transition-name: card-principal;
/* O navegador automaticamente animará a transição entre posições */
}
Caso de uso prático — galeria de imagens:
/* Cada imagem da galeria recebe um nome único */
.galeria img:nth-child(1) { view-transition-name: img-1; }
.galeria img:nth-child(2) { view-transition-name: img-2; }
/* Na página de detalhes, o mesmo nome é usado para a imagem ampliada */
O navegador calcula automaticamente a interpolação de posição, escala e recorte, criando uma sensação de continuidade visual.
7. Controle avançado com JavaScript
O objeto ViewTransition retornado por startViewTransition oferece hooks para controle fino:
async function transicaoControlada(url) {
const transition = document.startViewTransition(async () => {
// Carrega dados primeiro
const dados = await fetchData(url);
atualizarDOM(dados);
});
// Aguarda a animação terminar
await transition.finished;
// Ou cancela se necessário
// transition.skipTransition();
}
Para sincronizar com carregamento de dados pesados:
document.startViewTransition(async () => {
// Mostra skeleton loading enquanto carrega
mostrarSkeleton();
const dados = await fetch('/api/dados');
atualizarConteudo(dados);
esconderSkeleton();
});
8. Boas práticas, acessibilidade e suporte
A acessibilidade é fundamental — respeite a preferência do usuário por movimento reduzido:
@media (prefers-reduced-motion: reduce) {
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
}
}
Para performance, monitore o Cumulative Layout Shift (CLS) — transições bruscas podem causar saltos visuais. A API ajuda a mitigar isso, mas certifique-se de que os elementos tenham dimensões definidas antes da transição.
Suporte atual (2025): Chrome/Edge 111+, Firefox em desenvolvimento (flag experimental), Safari ainda sem suporte nativo. Para fallback, a API já degrada graciosamente — sem polyfill necessário em muitos casos.
Referências
- MDN Web Docs: View Transitions API — Documentação oficial completa com exemplos e especificações técnicas
- Chrome Developers: Smooth page transitions with the View Transitions API — Guia prático do Google com casos de uso SPA e MPA
- CSS-Tricks: View Transitions API: A Complete Guide — Tutorial abrangente com exemplos de animações customizadas
- Web.dev: View Transitions API for multi-page apps — Artigo focado em transições MPA com meta tag e configuração server-side
- Smashing Magazine: View Transitions API: Animating Page Transitions — Análise aprofundada com boas práticas de performance e acessibilidade
- W3C Specification: View Transitions API — Especificação oficial do W3C para consulta técnica detalhada