# Animando layouts de CSS Grid com CSS Anchor Positioning

> Como fazer as células de um grid animarem até a nova posição quando o espaço muda, sem JavaScript e sem View Transitions, com animações interrompíveis.

URL: https://dpw.dev/css/grid-animado-anchor-positioning/  
Publicado em: 2026-10-05  
Categoria: css  
Tags: animacao-css, layout, css-grid  
Autor: Tárcio Zemel

Quando o espaço disponível muda, um grid comum reposiciona as células de um salto. Dá para fazer essa reorganização acontecer com animação, e com animações interrompíveis, usando **CSS Anchor Positioning** e transições comuns. Sem JavaScript e sem View Transitions.

> Artigo baseado em [Animating CSS Grid Layouts with CSS Anchor Positioning](https://www.bram.us/2026/09/07/animating-css-grid-layouts-with-css-anchor-positioning/).

No <a href="https://cssday.nl/" target="_blank" rel="noopener noreferrer">CSS Day</a>, em junho, alguém perguntou ao autor como o Brave (o navegador) teria construído a New Tab Page dele, que exibe alguns tiles dispostos em grid.

O grid em si não tem nada de espetacular. O especial acontece ao redimensionar a viewport: conforme o espaço disponível muda, o grid se reorganiza de forma animada. As animações também são interrompíveis, o que indica que não há View Transitions em jogo.

Como eles fizeram? Não se sabe. Mas, para recriar o efeito, o caminho seria CSS Anchor Positioning com CSS Transitions comuns por cima.

Quem ainda não conhece Anchor Positioning pode começar pelo post <a href="https://www.bram.us/2026/02/28/anchors-aweigh-sotb2026/" target="_blank" rel="noopener noreferrer">Anchors Aweigh!</a>, que explica tudo o que é necessário sobre o recurso (com vídeo).

## A técnica

O efeito desejado é este: conforme o grid é redimensionado, as células animam até a nova posição.

<figure>
  <video autoplay loop muted playsinline>
    <source src="/images/blog/grid-animado-anchor-positioning/grid-reorganizando.webm" type="video/webm" />
  </video>
  <figcaption>Gravação da demonstração do grid animado.</figcaption>
</figure>

O truque é usar **CSS Anchor Positioning** e ancorar o conteúdo da célula na própria célula. Como não é possível ancorar conteúdo diretamente numa célula de grid (células de grid são conceitos virtuais), é preciso injetar uma div extra que ocupe o espaço disponível da célula e sirva de âncora.

As transições CSS comuns ficam responsáveis por animar as coisas conforme elas se deslocam.

```html
<div class="grid">
	<div class="cell">
		<div class="content">CONTENT</div>
	</div>
	<div class="cell">
		<div class="content">CONTENT</div>
	</div>
	…
</div>
```

```css
.grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, 6rem);
	gap: 1em;
}

.cell {
	height: auto;
	aspect-ratio: 1;

	anchor-scope: --a;
	anchor-name: --a;
}

.content {
	position: absolute;
	position-anchor: --a;
	inset: anchor(inside);
	width: 6rem;
	height: 6rem;

	transition: inset 0.2s ease;
}
```

São quatro detalhes que fazem o arranjo funcionar:

- Como nomes de âncora são globais por padrão, eles precisam ficar restritos à subárvore de cada célula. O `anchor-scope: --a;` cuida disso, permitindo que cada `.cell` reutilize o identificador `--a` sem conflitar com as outras.
- O `aspect-ratio: 1;` nas `.cell` garante que elas tenham tanta altura quanto largura.
- A declaração de `transition` garante que o `inset` faça a transição suave de um valor ao outro.
- As divs `.content` recebem dimensões explícitas (`width` e `height`). Sem isso, elas esticariam e comprimiriam durante a interpolação, conforme o grid é redimensionado.

Ao contrário das View Transitions, esta técnica não exige JavaScript nenhum e as animações são perfeitamente interrompíveis.

Ao redimensionar a viewport rapidamente para frente e para trás, os tiles não entram em fila esperando frames de animação ou promises de transição terminarem: redirecionam na hora, em pleno voo, para a posição recém-calculada.

Uma ressalva: por ora, isso não funciona no Firefox, porque ele não faz <a href="https://drafts.csswg.org/css-anchor-position-1/#interleaving" target="_blank" rel="noopener noreferrer">interleaving de estilo e layout</a> para Anchor Positioning. Em vez de resolver para valores em pixel interpoláveis, ele mantém o valor de `anchor()` no <a href="http://brm.us/value-processing" target="_blank" rel="noopener noreferrer">computed value time</a>.

## Demonstração

Esta é a demonstração construída para mostrar o comportamento:

[Exemplo no CodePen](https://codepen.io/anon/pen/ogBYjgm)

Redimensione o embed, ou o `.container` dentro da própria demonstração, para ver o grid se reorganizar.

Para algo de fidelidade maior (e mais próximo da New Tab Page do Brave):

[Exemplo no CodePen](https://codepen.io/anon/pen/01a07dd4-4d23-7e7b-9f41-3e0aa126751f)

<figure>
  <video autoplay loop muted playsinline>
    <source src="/images/blog/grid-animado-anchor-positioning/grid-animado-anchor-positioning.webm" type="video/webm" />
  </video>
  <figcaption>Gravação da demonstração de fidelidade maior.</figcaption>
</figure>

## Se este post pareceu familiar

O autor já <a href="https://bsky.app/profile/bram.us/post/3moe5buoab22w" target="_blank" rel="noopener noreferrer">havia compartilhado uma demonstração no Bluesky</a> sobre o assunto em junho, e só escreveu o post depois.

<a href="https://chriscoyier.net/" target="_blank" rel="noopener noreferrer">Chris Coyier</a> também cobriu a abordagem no Frontend Masters. No texto dele, ele relembra como o Masonry.js animava layouts fluidos e mostra como esse código traz aquele mesmo comportamento nativamente para o CSS: <a href="https://frontendmasters.com/blog/masonry-with-animation-in-css/" target="_blank" rel="noopener noreferrer">Masonry (with Animation) in CSS</a>.

---

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
