# 7 receitas de View Transitions para experimentar

> Sete animações prontas para páginas com View Transitions do CSS — pixel dissolve, wipe, rotação, círculo, diagonal, cortina e 3D flip.

URL: https://dpw.dev/css/7-receitas-de-view-transitions/  
Publicado em: 2026-04-23  
Categoria: css  
Tags: animacao-css  
Autor: Tárcio Zemel

View transitions são <em>realmente</em> muito legais. E não só isso: estão começando a aparecer <em>em todo lugar</em>. A primeira experiência com elas, em sua forma mais simples, costuma ser direta, mas, em muitos casos, envolvem várias partes trabalhando em conjunto.

> Artigo baseado em [7 View Transitions Recipes to Try](https://css-tricks.com/7-view-transitions-recipes-to-try/).

A melhor maneira de aprender algo novo costuma ser ver o código, usá-lo em prática e, a partir daí, construir em cima. Pensando nisso, este artigo reúne sete receitas de view transitions prontas para experimentar (uma extensão natural para quem já trabalha com <a href="/css/animacoes-css-introducao/" target="_blank">animações CSS</a>).

Uma observação rápida antes de prosseguir: no momento em que este texto foi escrito, view transitions já atingiram status <a href="https://web.dev/baseline/" target="_blank" rel="noopener noreferrer">Baseline</a>, com suporte em todos os principais navegadores. Ainda assim, certos tipos de animação podem ter variações no suporte entre navegadores, então, vale sempre verificar a compatibilidade antes de levar para produção.

## O setup

Antes de qualquer receita, é preciso preparar o terreno. O primeiro passo é habilitar view transitions com a at-rule `@view-transition`, tanto na página de origem quanto na de destino:

```css
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
    types: <transition-type>;
  }
}
```

O `<transition-type>` é um descritor customizável que funciona como um identificador da animação. <a href="https://css-tricks.com/what-on-earth-is-the-types-descriptor-in-view-transitions/" target="_blank" rel="noopener noreferrer">Types</a> são basicamente o nome da animação que se dá a uma transição específica — isso evita conflitos quando múltiplas transições operam ao mesmo tempo.

Repare que o bloco está envolvido por uma media query `prefers-reduced-motion: no-preference`. Nem todo mundo quer movimento nas páginas, e essa é uma preferência que pode ser definida no nível do sistema operacional; respeitá-la é parte de fazer <a href="/acessibilidade/acessibilidade-css/">animações acessíveis</a>.

As animações em si são aplicadas via:

```css
html:active-view-transition-type(<transition-type>)::view-transition-old(root) {
  animation: a-cool-outgoing-animation 1.4s ease forwards;
}

html:active-view-transition-type(<transition-type>)::view-transition-new(root) {
  animation: a-cool-incoming-animation 1.4s ease forwards;
}
```

O seletor de pseudo-classe `:active-view-transition-type()` casa com o type definido. Em um exemplo concreto:

```css
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
    types: bounce;
  }
}

/* A página "atual" */
html:active-view-transition-type(bounce)::view-transition-old(root) {
  animation: bounce-in 1.4s ease forwards;
}

/* A página para onde se está transicionando */
html:active-view-transition-type(bounce)::view-transition-new(root) {
  animation: bounce-in 1.4s ease forwards;
}
```

Com esse esqueleto estabelecido, todas as receitas a seguir seguem o mesmo padrão: definir um `type`, aplicar uma animação de saída ao `::view-transition-old(root)` e uma animação de entrada ao `::view-transition-new(root)`.

## Pixelate dissolve

Esse efeito é parecido com um cross-fade simples, mas com um borrão degradando a transição: a página de saída desfoca e some, enquanto a nova entra voltando do desfoque para o estado nítido.

<video controls playsinline preload="metadata">
  <source src="/images/blog/7-receitas-de-view-transitions/pixelate-dissolve.webm" type="video/webm" />
</video>

```css
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
    types: pixelate-dissolve;
  }
}

html:active-view-transition-type(pixelate-dissolve)::view-transition-old(root) {
  animation: pixelate-out 1.4s ease forwards;
}

html:active-view-transition-type(pixelate-dissolve)::view-transition-new(root) {
  animation: pixelate-in 1.4s ease forwards;
}

@keyframes pixelate-out {
  0% {
    filter: blur(0px);
    opacity: 1;
  }
  100% {
    filter: blur(40px);
    opacity: 0;
  }
}

@keyframes pixelate-in {
  0% {
    filter: blur(40px);
    opacity: 0;
  }
  100% {
    filter: blur(0px);
    opacity: 1;
  }
}
```

## Wipe up

Essa receita usa a propriedade <a href="https://youtu.be/Q-7bVgZQsjk" target="_blank" rel="noopener noreferrer">`clip-path`</a> para produzir um wipe para cima: o conteúdo da nova página desliza de baixo para cima, substituindo o conteúdo "antigo".

A mecânica é a seguinte: a página de saída parte do valor padrão `inset(0 0 0 0)` e tem o parâmetro inferior levado a `100%`, criando um movimento de cima para baixo. A nova página começa recortada a partir do topo em `100%` e desce até `0`.

<video controls playsinline preload="metadata">
  <source src="/images/blog/7-receitas-de-view-transitions/wipe-up.webm" type="video/webm" />
</video>

```css
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
    types: wipe-up;
  }
}

html:active-view-transition-type(wipe-up)::view-transition-old(root) {
  animation: wipe-out 1.4s ease forwards;
}

html:active-view-transition-type(wipe-up)::view-transition-new(root) {
  animation: wipe-in 1.4s ease forwards;
}

@keyframes wipe-out {
  from {
    clip-path: inset(0 0 0 0);
  }
  to {
    clip-path: inset(0 0 100% 0);
  }
}

@keyframes wipe-in {
  from {
    clip-path: inset(100% 0 0 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}
```

Dá para variar o efeito ajustando os parâmetros do `inset()`. Para um wipe da esquerda para a direita:

```css
@keyframes wipe-out {
  from {
    clip-path: inset(0 0 0 0);
  }
  to {
    clip-path: inset(0 0 0 100%);
  }
}

@keyframes wipe-in {
  from {
    clip-path: inset(0 100% 0 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}
```

<video controls playsinline preload="metadata">
  <source src="/images/blog/7-receitas-de-view-transitions/wipe-right.webm" type="video/webm" />
</video>

E, para um wipe de cima para baixo:

```css
@keyframes wipe-out {
  from {
    clip-path: inset(0 0 0 0);
  }
  to {
    clip-path: inset(100% 0 0 0);
  }
}

@keyframes wipe-in {
  from {
    clip-path: inset(0 0 100% 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}
```

<video controls playsinline preload="metadata">
  <source src="/images/blog/7-receitas-de-view-transitions/wipe-down.webm" type="video/webm" />
</video>

## Rotate in-out

Essa próxima é um pouco, digamos, estranha. Definitivamente não é a coisa mais prática do mundo, mas serve para mostrar o quanto view transitions podem ser estendidas.

O efeito combina as funções `scale()` e `rotate()`: a página de saída é reduzida a zero e rotacionada em 180 graus no sentido horário, enquanto a nova página entra escalando de zero e girando -180 graus (sentido anti-horário).

Ajustes de opacidade reforçam a ilusão de saída e chegada do conteúdo.

<video controls playsinline preload="metadata">
  <source src="/images/blog/7-receitas-de-view-transitions/rotate-in-out.webm" type="video/webm" />
</video>

```css
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
    types: zoom-rotate;
  }
}

html:active-view-transition-type(zoom-rotate)::view-transition-old(root) {
  animation: zoom-rotate-out 1.4s ease forwards;
  transform-origin: center;
}

html:active-view-transition-type(zoom-rotate)::view-transition-new(root) {
  animation: zoom-rotate-in 1.4s ease forwards;
  transform-origin: center;
}

@keyframes zoom-rotate-out {
  to {
    transform: scale(0) rotate(180deg);
    opacity: 0;
  }
}

@keyframes zoom-rotate-in {
  from {
    transform: scale(0) rotate(-180deg);
    opacity: 0;
  }
}
```

## Circle wipe-out

Esse efeito é mais sutil que o anterior. Ele aparece melhor quando se transiciona entre conteúdos visualmente distintos e fica mais harmônico quando as duas páginas compartilham cores de fundo parecidas.

Uma forma circular parte do centro usando a função `circle()` dentro de `clip-path`, expandindo de 0% (invisível) até 150% (ultrapassando as bordas da página), cobrindo toda a viewport.

<video controls playsinline preload="metadata">
  <source src="/images/blog/7-receitas-de-view-transitions/circle-wipe-out.webm" type="video/webm" />
</video>

```css
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
    types: circular-wipe;
  }
}

html:active-view-transition-type(circular-wipe)::view-transition-old(root) {
  animation: circle-wipe-out 1.4s ease forwards;
}

html:active-view-transition-type(circular-wipe)::view-transition-new(root) {
  animation: circle-wipe-in 1.4s ease forwards;
}

@keyframes circle-wipe-out {
  to {
    clip-path: circle(0% at 50% 50%);
  }
}

@keyframes circle-wipe-in {
  from {
    clip-path: circle(0% at 50% 50%);
  }
  to {
    clip-path: circle(150% at 50% 50%);
  }
}
```

## Diagonal push

Essa receita empurra a página "antiga" para fora enquanto a "nova" entra em diagonal, do canto inferior direito em direção ao superior esquerdo (ou qualquer outra variação direcional).

Para o movimento saindo pelo canto inferior direito, a animação translada a -100% nos eixos X e Y, empurrando o conteúdo para fora da tela.

A nova página se aproxima do canto oposto, voltando à posição padrão em 0%. A gradação de opacidade suaviza a transição.

<video controls playsinline preload="metadata">
  <source src="/images/blog/7-receitas-de-view-transitions/diagonal-push.webm" type="video/webm" />
</video>

```css
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
    types: diagonal-push;
  }
}

html:active-view-transition-type(diagonal-push)::view-transition-old(root) {
  animation: diagonal-out 1.4s ease forwards;
}

html:active-view-transition-type(diagonal-push)::view-transition-new(root) {
  animation: diagonal-in 1.4s ease forwards;
}

@keyframes diagonal-out {
  to {
    transform: translate(-100%, -100%);
    opacity: 0;
  }
}

@keyframes diagonal-in {
  from {
    transform: translate(100%, 100%);
    opacity: 0;
  }
}
```

## Curtain reveal

Esse efeito simula uma cortina de teatro fechando sobre a página antiga e abrindo para revelar a nova.

A função `inset()` define retângulos posicionados a 50% das bordas direita e esquerda. Durante a fase de saída, esses insets ficam em 50%; durante a fase de entrada, reduzem para 0, criando o efeito visual de conteúdo emergindo do centro simultaneamente em direção às bordas esquerda e direita.

<video controls playsinline preload="metadata">
  <source src="/images/blog/7-receitas-de-view-transitions/curtain-reveal.webm" type="video/webm" />
</video>

```css
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
    types: curtain;
  }
}

html:active-view-transition-type(curtain)::view-transition-old(root) {
  animation: curtain-out 1.4s ease forwards;
}

html:active-view-transition-type(curtain)::view-transition-new(root) {
  animation: curtain-in 1.4s ease forwards;
}

@keyframes curtain-out {
  from {
    clip-path: inset(0 0 0 0);
  }
}

@keyframes curtain-in {
  from {
    clip-path: inset(0 50% 0 50%);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}
```

## 3D flip

Essa receita simula a animação de uma carta sendo virada: uma página gira para fora ao longo do eixo Z enquanto a página seguinte gira para dentro, fingindo ser o verso e o anverso de uma única carta.

<video controls playsinline preload="metadata">
  <source src="/images/blog/7-receitas-de-view-transitions/flip-3d.webm" type="video/webm" />
</video>

```css
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
    types: flip-3d;
  }
}

html:active-view-transition-type(flip-3d)::view-transition-old(root) {
  animation: flip-out 1.4s ease forwards;
}

html:active-view-transition-type(flip-3d)::view-transition-new(root) {
  animation: flip-in 1.4s ease forwards;
}

@keyframes flip-out {
  0% {
    transform: rotateY(0deg) translateX(0vw);
  }
  100% {
    transform: rotateY(-90deg) translateX(-100vw);
    opacity: 1;
  }
}

@keyframes flip-in {
  0% {
    transform: rotateY(90deg) translateX(100vw);
  }
  100% {
    transform: rotateY(0deg) translateX(0vw);
  }
}
```

## E aí, alguma receita legal para compartilhar?

A ideia dessas sete receitas é servir de ponto de partida: peças pequenas o suficiente para serem copiadas, testadas e combinadas em efeitos mais complexos. Sempre há espaço para mais exemplos e mais ideias criativas em cima de view transitions.

Para quem quiser explorar mais a fundo, Bramus mantém uma <a href="https://page-transitions.style/spa/" target="_blank" rel="noopener noreferrer">coleção interativa de demos</a> que vale a visita, com implementações que mostram muito bem o quanto ainda dá para inventar com esse recurso.

---

Fonte: [dpw - desenvolvimento para web](https://dpw.dev/) (pt-BR).
Guia para agentes: https://dpw.dev/llms.txt
Índice completo: https://dpw.dev/sitemap-index.xml
Feed: https://dpw.dev/rss.xml
