CSS anchor positioning: o fim das gambiarras de tooltip e popover
1. O Problema Histórico: Posicionamento de Elementos Flutuantes
Por anos, desenvolvedores web enfrentaram um pesadelo recorrente: posicionar tooltips, popovers e menus dropdown de forma precisa e responsiva. A abordagem clássica dependia de JavaScript puro — ou bibliotecas como Popper.js — para calcular coordenadas com getBoundingClientRect(), monitorar eventos de scroll e redimensionamento, e ajustar manualmente as posições.
As gambiarras eram muitas: position: absolute com margens negativas, combinações de top e left calculados dinamicamente, e hacks com transform: translate() para evitar reflows. Em layouts responsivos, o cenário piorava: ao zoomar ou redimensionar a janela, tooltips quebravam, sobrepunham conteúdo ou simplesmente desapareciam.
O problema central era que CSS não oferecia uma forma declarativa de dizer: "posicione este elemento em relação àquele outro". Tudo precisava ser resolvido em tempo de execução com JavaScript, gerando complexidade, bugs de layout shift (CLS) e manutenção dolorosa.
2. Introdução ao CSS Anchor Positioning API
O CSS Anchor Positioning API resolve esse problema de forma nativa. A ideia é simples: qualquer elemento pode ser uma âncora (anchor) e outros elementos podem se posicionar em relação a ela como alvos (targets).
As propriedades fundamentais são:
anchor-name: define um identificador para o elemento âncora (ex:--meu-botao)position-anchor: no elemento alvo, referencia a âncora pelo nomeanchor(): função que calcula posições relativas à âncorainset-area: posiciona o alvo em áreas predefinidas ao redor da âncora
O suporte atual inclui Chrome 125+, Edge 125+, e Safari Technology Preview. Firefox está em desenvolvimento. Para produção, é recomendado usar como progressive enhancement.
3. Sintaxe Básica: Vinculando um Popover a um Botão
Vamos ao exemplo mais simples: um botão que abre um popover posicionado acima dele.
<button id="meu-botao" popovertarget="meu-popover">Abrir</button>
<div id="meu-popover" popover>
Conteúdo do popover
</div>
<style>
#meu-botao {
anchor-name: --meu-botao;
}
#meu-popover {
position-anchor: --meu-botao;
inset-area: top;
}
</style>
Com apenas três linhas de CSS, o popover se posiciona automaticamente acima do botão. Quando o botão é clicado, o popover abre sem uma linha de JavaScript. O navegador gerencia scroll, redimensionamento e posicionamento.
4. Controle Fino de Posicionamento com inset-area
A propriedade inset-area aceita combinações poderosas:
/* Posicionamento básico */
inset-area: top; /* acima, centralizado */
inset-area: bottom; /* abaixo, centralizado */
inset-area: left; /* à esquerda, centralizado */
inset-area: right; /* à direita, centralizado */
/* Combinações com duas palavras */
inset-area: top left; /* canto superior esquerdo */
inset-area: bottom right; /* canto inferior direito */
/* Centralizado em relação à âncora */
inset-area: center; /* exatamente sobre a âncora */
Para ajustes finos, use a função anchor():
#meu-popover {
position-anchor: --meu-botao;
top: anchor(--meu-botao bottom + 8px);
left: anchor(--meu-botao left);
}
Para prevenir overflow em telas pequenas, use position-try-fallbacks:
#meu-popover {
position-anchor: --meu-botao;
inset-area: top;
position-try-fallbacks: bottom, left, right;
}
Isso instrui o navegador: "tente top primeiro; se não couber, tente bottom; depois left; depois right".
5. Casos de Uso Práticos: Tooltips e Popovers Sem JavaScript
Tooltip em hover com CSS puro
<button class="tooltip-trigger" aria-describedby="tooltip1">
Salvar
<span class="tooltip" id="tooltip1">Salva as alterações atuais</span>
</button>
<style>
.tooltip-trigger {
anchor-name: --trigger;
position: relative;
}
.tooltip {
position-anchor: --trigger;
inset-area: bottom;
display: none;
background: #333;
color: #fff;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
}
.tooltip-trigger:hover .tooltip,
.tooltip-trigger:focus .tooltip {
display: block;
}
</style>
Popover de menu dropdown
<button popovertarget="menu-dropdown" style="anchor-name: --menu-btn">
Opções ▼
</button>
<nav id="menu-dropdown" popover style="position-anchor: --menu-btn; inset-area: bottom">
<ul>
<li><a href="#">Editar</a></li>
<li><a href="#">Duplicar</a></li>
<li><a href="#">Excluir</a></li>
</ul>
</nav>
Modal de confirmação centralizado na âncora
<button popovertarget="confirm-modal" style="anchor-name: --excluir-btn">
Excluir item
</button>
<div id="confirm-modal" popover style="position-anchor: --excluir-btn; inset-area: center">
<p>Tem certeza que deseja excluir?</p>
<button popovertarget="confirm-modal" popovertargetaction="hide">Cancelar</button>
<button>Confirmar</button>
</div>
6. Resolvendo Problemas Comuns com Fallbacks
Evitando layout shift (CLS)
Diferente de soluções JavaScript que causam reflow ao reposicionar elementos, o Anchor Positioning calcula a posição antes do paint. O elemento já nasce na posição correta, sem saltos visuais.
Comportamento em telas pequenas
#popover {
position-anchor: --ancora;
inset-area: right;
position-try-options: flip-block, flip-inline;
}
flip-block inverte de cima para baixo; flip-inline inverte de esquerda para direita. Isso garante que o popover sempre fique visível.
Fallback para navegadores sem suporte
#popover {
/* Fallback: posicionamento absoluto tradicional */
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
/* Anchor Positioning para navegadores compatíveis */
position-anchor: --ancora;
inset-area: bottom;
}
Navegadores modernos ignoram o fallback e usam o anchor; navegadores antigos usam o posicionamento absoluto.
7. Comparação com Abordagens Antigas
| Característica | JavaScript (Popper.js) | Gambiarra CSS | Anchor Positioning |
|---|---|---|---|
| Código necessário | 50+ linhas JS + CSS | 20+ linhas CSS + hacks | 3-5 linhas CSS |
| Performance | Reflow constante, listeners | Reflow em zoom/scroll | Zero reflow forçado |
| Responsividade | Precisa de resize observer | Quebra facilmente | Nativa e automática |
| Acessibilidade | Depende de implementação | ARIA manual + foco manual | Nativa com popover |
| Manutenção | Alta (atualizar libs) | Média (hacks quebram) | Baixa (especificação estável) |
8. Exemplo Completo: Sistema de Tooltips Temáticos
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tooltips com Anchor Positioning</title>
<style>
:root {
--tooltip-bg: #333;
--tooltip-color: #fff;
--tooltip-delay: 0.3s;
}
[data-theme="light"] {
--tooltip-bg: #f0f0f0;
--tooltip-color: #333;
}
.btn {
anchor-name: --btn;
padding: 8px 16px;
border: 1px solid #ccc;
border-radius: 4px;
cursor: pointer;
position: relative;
}
.tooltip {
position-anchor: --btn;
inset-area: top;
background: var(--tooltip-bg);
color: var(--tooltip-color);
padding: 6px 12px;
border-radius: 6px;
font-size: 13px;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity var(--tooltip-delay) ease;
}
.btn:hover .tooltip,
.btn:focus-visible .tooltip {
opacity: 1;
}
.tooltip::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 6px solid transparent;
border-top-color: var(--tooltip-bg);
}
</style>
</head>
<body>
<button class="btn">
Salvar
<span class="tooltip" role="tooltip">Salva as alterações atuais</span>
</button>
<button class="btn">
Excluir
<span class="tooltip" role="tooltip">Remove permanentemente</span>
</button>
<div data-theme="light">
<button class="btn">
Modo claro
<span class="tooltip" role="tooltip">Tema alternativo</span>
</button>
</div>
</body>
</html>
Este exemplo demonstra:
- Tooltips sem JavaScript, apenas HTML + CSS
- Suporte a temas claro/escuro com CSS variables
- Transição suave com delay
- Seta indicadora estilizada com pseudo-elemento
- Acessibilidade com role="tooltip" e foco via teclado
O resultado é um sistema de tooltips performático, acessível e fácil de manter — exatamente o que o CSS Anchor Positioning promete entregar.
Referências
- MDN Web Docs: CSS Anchor Positioning — Documentação oficial completa com exemplos interativos e tabela de suporte dos navegadores
- Chrome Developers: CSS Anchor Positioning API — Artigo técnico do Chrome团队 com casos de uso avançados e demonstrações
- W3C CSS Anchor Positioning Specification — Especificação oficial do W3C com detalhes técnicos do algoritmo de posicionamento
- web.dev: Anchor positioning and popover — Tutorial prático de como combinar anchor positioning com a API popover nativa
- CSS-Tricks: A Complete Guide to CSS Anchor Positioning — Guia completo com exemplos visuais, comparações e dicas de fallback
- Smashing Magazine: CSS Anchor Positioning Is Here — Artigo aprofundado sobre implementação em projetos reais e considerações de acessibilidade