View Transitions API: como criar transições de página fluidas
Aprenda a criar transições fluidas entre estados e páginas com a View Transitions API, CSS, fallback e acessibilidade.

Uma troca brusca entre duas telas pode fazer o usuário perder a referência de onde estava e para onde foi.
Isso acontece em galerias, filtros, navegação entre páginas e componentes que mudam de tamanho ou posição.
Animações ajudam a preservar essa continuidade, mas implementá-las manualmente costuma exigir cópias de elementos, cálculos de coordenadas e controle delicado do DOM.
A View Transitions API transfere boa parte desse trabalho para o navegador.
Ela captura o estado visual antes e depois de uma mudança, cria pseudo-elementos temporários e permite animar a passagem usando CSS.
O conteúdo continua sendo atualizado normalmente; a transição funciona como uma camada visual sobre essa alteração.
Neste guia, você vai criar uma transição básica, personalizar a animação, conectar um elemento entre uma lista e uma tela de detalhes e entender as diferenças entre aplicações de página única e sites multipágina.
Também veremos fallback, acessibilidade, compatibilidade e os erros que fazem uma animação bonita prejudicar a experiência.
O que é a View Transitions API?
A View Transitions API é um conjunto de recursos da plataforma web para animar a passagem entre estados visuais.
Ela pode envolver uma mudança dentro do mesmo documento, comum em SPAs, ou uma navegação entre documentos diferentes da mesma origem, típica de sites multipágina.
De acordo com a documentação da API no MDN, o navegador captura representações do estado antigo e do novo e disponibiliza uma árvore de pseudo-elementos para a animação.
O desenvolvedor decide quando o DOM muda e pode personalizar duração, curva, direção e elementos participantes com CSS.
A API não cria uma nova forma de navegação nem transforma um site em SPA. Ela envolve uma mudança que já aconteceria e adiciona continuidade visual.
Por isso, funciona melhor como aprimoramento progressivo: se não houver suporte, o conteúdo ainda precisa mudar corretamente, apenas sem a animação.
Como uma View Transition funciona
- O navegador captura o estado visual atual.
- A função de atualização altera o DOM ou a navegação carrega o novo documento.
- O navegador captura o novo estado.
- As duas representações são colocadas em pseudo-elementos temporários.
- Uma animação CSS faz a transição do estado antigo para o novo.
- Ao terminar, a camada temporária é removida e a página permanece no estado final real.
Por padrão, a raiz da página recebe um efeito de cross-fade. Elementos com um view-transition-name próprio ganham grupos separados e podem animar posição, dimensões e transformação.
O conteúdo antigo é uma captura, enquanto a nova visualização se torna o estado ativo.
Transição no mesmo documento
Uma transição no mesmo documento acontece quando JavaScript modifica a interface sem carregar outra página.
Exemplos incluem trocar abas, abrir detalhes de um produto, reordenar cartões, mudar o tema ou navegar com o roteador de uma SPA.
O método document.startViewTransition() recebe uma função que executa a atualização.
O navegador captura o estado anterior antes de chamar essa função e espera a conclusão dela antes de preparar a nova captura.
A referência de transições no mesmo documento detalha esse processo e os pseudo-elementos gerados.
Primeiro exemplo com JavaScript
Considere um botão que alterna a classe de um painel. Separe a mudança de estado em uma função e inclua uma verificação de suporte:
const painel = document.querySelector('.painel');
const botao = document.querySelector('.alternar-layout');
function atualizarInterface() {
painel.classList.toggle('painel--detalhado');
}
botao.addEventListener('click', () => {
if (!document.startViewTransition) {
atualizarInterface();
return;
}
document.startViewTransition(atualizarInterface);
});
Em navegadores compatíveis, a troca recebe o efeito padrão. Nos demais, a classe muda imediatamente. Essa estrutura é importante: o resultado funcional não depende da API.
Se callbacks e promises ainda causam confusão, consulte o guia de JavaScript assíncrono.
Como personalizar a animação com CSS
O efeito padrão pode ser substituído com animações aplicadas às capturas antiga e nova.
O exemplo cria uma saída curta e uma entrada ligeiramente deslocada:
@keyframes sair {
to {
opacity: 0;
transform: translateY(-8px);
}
}
@keyframes entrar {
from {
opacity: 0;
transform: translateY(8px);
}
}
::view-transition-old(root) {
animation: 140ms ease-in both sair;
}
::view-transition-new(root) {
animation: 220ms ease-out both entrar;
}
Movimentos curtos e rápidos costumam comunicar continuidade sem bloquear o usuário.
Use as práticas do artigo sobre CSS moderno para organizar camadas, variáveis e regras responsivas, especialmente quando diferentes componentes ganham animações próprias.
Entendendo os pseudo-elementos
::view-transition: contêiner da camada temporária.::view-transition-group(nome): controla posição e dimensões do grupo.::view-transition-image-pair(nome): reúne as representações antiga e nova.::view-transition-old(nome): captura do estado anterior.::view-transition-new(nome): representação do novo estado.
O nome root representa a página inteira. Quando um elemento recebe um nome específico, substitua root por esse valor nos seletores.
Eles são pseudo-elementos especiais criados somente durante a transição; nosso guia sobre pseudo-elementos em CSS ajuda a revisar a lógica geral desse recurso.
Como animar um elemento compartilhado
Um dos usos mais interessantes é fazer uma miniatura da lista crescer até ocupar a área principal na tela de detalhes.
A imagem antiga e a nova não precisam ser o mesmo nó do DOM. Elas precisam representar o mesmo objeto visual e compartilhar um nome durante a transição.
.produto-selecionado .produto-imagem,
.detalhes-produto .produto-imagem {
view-transition-name: imagem-produto;
}
::view-transition-group(imagem-produto) {
animation-duration: 320ms;
animation-timing-function: cubic-bezier(.2, .8, .2, 1);
}
::view-transition-old(imagem-produto),
::view-transition-new(imagem-produto) {
mix-blend-mode: normal;
}

O navegador interpola posição e tamanho entre as duas capturas. Isso comunica que o usuário não abriu um objeto diferente: o item da lista se tornou o conteúdo detalhado.
Use esse efeito onde existe continuidade semântica real, não apenas para decorar a tela.
Nomes precisam ser únicos
Dois elementos renderizados não podem ter o mesmo view-transition-name ao mesmo tempo.
Em uma grade, atribua o nome somente ao item selecionado antes de iniciar a mudança ou gere nomes exclusivos quando cada cartão precisar participar.
Se houver duplicidade, a transição correspondente pode ser ignorada.
Transições entre páginas diferentes
Sites multipágina podem ativar transições em navegações qualificadas entre documentos da mesma origem.
Nesse caso, não é necessário chamar startViewTransition(). As duas páginas devem incluir a regra de adesão:
@view-transition {
navigation: auto;
}
Os documentos podem usar o mesmo view-transition-name em elementos correspondentes, como a imagem de um artigo na listagem e na página individual.
A documentação de transições entre documentos explica os requisitos de mesma origem e os eventos pageswap e pagereveal.
A compatibilidade desse modo ainda é menos uniforme que a das transições no mesmo documento.
Portanto, o link precisa continuar sendo uma navegação HTML normal. Nunca impeça o carregamento da página apenas porque uma animação não começou.
View Transitions em frameworks
React, Vue e outros frameworks atualizam o DOM por meio de seus próprios ciclos.
A chamada precisa envolver a atualização que realmente será confirmada na interface, não apenas a alteração de uma variável que só produzirá renderização depois.
Integrações oficiais do framework ou do roteador devem ser preferidas quando disponíveis.
Em roteamento, trate a API como uma camada do fluxo de navegação. Preserve histórico, foco, carregamento e estados de erro.
Para entender a diferença entre rotas e renderizações antes de adicionar movimento, veja Next.js para iniciantes.
Não copie uma integração específica sem conferir a versão do framework usado no projeto.
Promises e ciclo de vida
startViewTransition() retorna um objeto ViewTransition. Ele oferece promises úteis para momentos diferentes:
updateCallbackDone: a função que atualiza o DOM terminou.ready: a árvore de pseudo-elementos está pronta para animar.finished: a animação acabou e o novo estado está visível.
Essas etapas permitem coordenar a Web Animations API, limpar estados temporários ou mover o foco após a mudança.
Não condicione a atualização funcional à conclusão da animação. Se a transição for ignorada, a interface ainda deve chegar ao mesmo resultado.
Acessibilidade e redução de movimento
Movimento excessivo pode causar desconforto, distrair e tornar a navegação mais lenta para algumas pessoas.
Respeite prefers-reduced-motion e ofereça uma alteração praticamente imediata:
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*) {
animation-duration: 0.01ms;
}
}
A transição não administra foco, anúncio para leitores de tela nem significado do novo conteúdo.
Depois de abrir uma tela de detalhes, confirme se o foco permanece adequado e se títulos e regiões continuam estruturados.
O guia de acessibilidade web apresenta uma base prática para essas decisões.
Animações devem esclarecer hierarquia e relação espacial. Se a pessoa precisa esperar para agir ou não entende onde o conteúdo terminou, o efeito está trabalhando contra a interface.
Os conceitos de UX para desenvolvedores ajudam a avaliar esse equilíbrio.

Impacto no desempenho
As capturas e animações consomem memória e trabalho de renderização.
Páginas grandes, muitos grupos nomeados, filtros visuais pesados e transições longas podem produzir travamentos em dispositivos modestos. Teste com limitação de CPU, telas diferentes e dados reais.
- Anime somente elementos que ajudam a explicar a mudança.
- Prefira transformações e opacidade a efeitos visuais complexos.
- Mantenha durações curtas e consistentes.
- Evite iniciar várias transições concorrentes sem necessidade.
- Carregue imagens de destino com dimensões e proporções previsíveis.
- Observe interação, estabilidade visual e responsividade antes e depois.
Uma transição não corrige carregamento lento nem substitui otimização. Compare métricas no artigo sobre Core Web Vitals e valide que o efeito não mascara um atraso real na navegação.
Compatibilidade e fallback
O suporte varia entre recursos da API e versões dos navegadores.
O MDN classifica a interface principal para transições no mesmo documento como amplamente disponível em navegadores recentes, mas alerta que dispositivos antigos e partes específicas podem divergir.
Transições entre documentos ainda exigem atenção adicional à matriz de suporte.
Use detecção de recurso, não identificação pelo nome do navegador. Para SPAs, verifique document.startViewTransition.
Para MPAs, mantenha links normais e trate a regra CSS como aprimoramento. A própria orientação de uso do MDN demonstra esse padrão de fallback.
Como depurar transições
- Confirme que a função de atualização realmente muda o DOM.
- Verifique se não existem nomes duplicados na tela.
- Reduza a velocidade ou pause a animação nas ferramentas do navegador.
- Inspecione a árvore temporária de pseudo-elementos.
- Teste sem CSS personalizado para isolar o problema.
- Confira erros e rejeições das promises no console.
- Repita com redução de movimento e em uma largura menor.
Quando a nova visualização depende de dados assíncronos, decida o que deve acontecer antes da captura.
Esperar uma chamada lenta dentro do callback pode congelar visualmente o estado anterior.
Em muitos casos, é melhor carregar os dados, preparar o estado e iniciar a transição apenas quando a mudança estiver pronta.
Erros comuns
- Depender da animação: navegadores sem suporte deixam de atualizar a tela.
- Reutilizar um nome: dois elementos ativos recebem o mesmo identificador.
- Animar tudo: a interface vira um conjunto de movimentos sem hierarquia.
- Ignorar redução de movimento: a experiência desrespeita uma preferência do usuário.
- Bloquear durante a transição: carregamentos longos parecem travamento.
- Esquecer o foco: a mudança visual funciona, mas a navegação por teclado se perde.
- Testar apenas no desktop: a captura fica pesada ou inadequada no celular.
- Confundir beleza com desempenho: o efeito esconde uma rota lenta sem resolver a causa.
Checklist de implementação
- A mudança funciona corretamente sem View Transitions.
- A animação explica uma relação espacial ou continuidade real.
- Os nomes dos elementos são únicos durante a captura.
- Há fallback por detecção de recurso.
- A preferência por redução de movimento é respeitada.
- Foco, teclado e leitores de tela continuam funcionando.
- A duração não atrasa uma ação importante.
- O teste inclui celular e dispositivo com menor desempenho.
- Não houve regressão perceptível nas métricas da página.
- A integração segue a versão atual do framework e do roteador.
Perguntas frequentes
View Transitions substitui animações CSS?
Não. A API cria capturas e pseudo-elementos para representar a mudança, mas a personalização continua usando animações CSS ou, em casos avançados, a Web Animations API.
Ela simplifica a transição entre estados, não substitui as ferramentas de movimento.
A API funciona sem JavaScript?
Em navegações entre documentos da mesma origem, a adesão básica pode ser feita somente com a regra @view-transition.
Em mudanças dentro do mesmo documento, JavaScript chama startViewTransition() e atualiza a interface.
É possível animar somente um componente?
Sim. Você pode nomear apenas os elementos relevantes e manter o restante no comportamento padrão.
Recursos mais novos também permitem transições com escopo em um elemento, mas a compatibilidade precisa ser conferida antes do uso em produção.
A transição melhora o Core Web Vitals?
Não automaticamente. Ela pode melhorar a percepção de continuidade, mas também consome recursos.
LCP, INP e CLS precisam ser medidos separadamente. Uma animação não transforma uma resposta lenta em uma página rápida.
Posso usar em React e Next.js?
Sim, desde que a transição envolva corretamente a atualização confirmada pelo framework ou pelo roteador.
Como as integrações evoluem, consulte a documentação da versão usada e não dependa de exemplos antigos sem testar.
O que acontece quando a animação falha?
A atualização do DOM pode continuar mesmo se a parte visual for ignorada.
O código deve tratar a transição como aprimoramento e evitar que uma promise rejeitada interrompa a funcionalidade principal.
Conclusão
A View Transitions API torna viável criar continuidade visual entre estados sem reconstruir manualmente cada elemento em movimento.
Com uma chamada JavaScript, pseudo-elementos CSS e nomes compartilhados, uma grade pode se transformar em detalhes, uma aba pode mudar de conteúdo e páginas da mesma origem podem ganhar uma passagem mais suave.
O melhor resultado vem da moderação. Comece pelo fallback, escolha uma mudança que realmente se beneficie de contexto espacial e adicione movimento curto e acessível.
Depois, teste compatibilidade e desempenho em dispositivos reais. A animação deve ajudar a pessoa a entender a interface; se ela vira o centro da experiência, provavelmente passou do ponto.