CSS Anchor Positioning e Popover API: Chega de JS para Popups em 2026
前端工程
CSS Anchor Positioning: A "Proclamação de Emancipação" para Devs Frontend
Todo desenvolvedor frontend já experimentou essa dor: usar JS para calcular posições de Tooltip, lidar com overflow de limites, escutar eventos de scroll e resize... Agora, o CSS pode lidar com tudo isso nativamente.
Revisão histórica: Em 2016 usávamos Popper.js, em 2020 Floating UI, e em 2026 finalmente temos posicionamento de âncora CSS nativo. Após 10 anos, o posicionamento de popups não é mais um trabalho de JS.
Evolução do Posicionamento com JS para o Posicionamento com CSS
2016 jQuery offset() + cálculo manual
Recalcular em cada scroll/resize
2020 Floating UI / Popper.js
Auto-flip, offset, detecção de limites
Mas ainda requer init e destroy com JS
2024 CSS Anchor Positioning (Chrome 125+)
Posicionamento declarativo CSS puro
O navegador gerencia limites e scroll nativamente
2026 Anchor Positioning + Popover API
Popups CSS puro: toggle zero-JS, posicionamento zero-JS
Solução declarativa completa de popups
anchor-name e position-anchor
Uso Básico
<div class="card">
<button class="trigger">Mais Ações</button>
<div class="dropdown">Conteúdo do dropdown</div>
</div>
.trigger {
anchor-name: --my-anchor;
}
.dropdown {
position: fixed;
position-anchor: --my-anchor;
top: anchor(bottom);
left: anchor(left);
}
Referência da Função anchor()
.tooltip {
position: fixed;
position-anchor: --trigger-anchor;
/* Relativo às bordas da âncora */
top: anchor(bottom);
bottom: anchor(top);
left: anchor(left);
right: anchor(right);
/* Pontos centrais da âncora */
left: anchor(50%);
top: anchor(50%);
/* Com offset */
top: calc(anchor(bottom) + 8px);
left: calc(anchor(left) - 4px);
}
position-area: Posicionamento em Grade de Nove Células
Sintaxe de Nove Células
┌─────────────┬─────────────┬─────────────┐
│ top left │ top center│ top right │
│ │ │ │
├─────────────┼─────────────┼─────────────┤
│ center left │ center │ center right│
│ │ │ │
├─────────────┼─────────────┼─────────────┤
│ bottom left │bottom center│ bottom right│
│ │ │ │
└─────────────┴─────────────┴─────────────┘
.tooltip-below {
position-area: bottom center;
}
.tooltip-right {
position-area: center right;
}
.dropdown-below-left {
position-area: bottom left;
}
position-fallback e Estratégia de Fallback Multinível
Auto-Flip por Overflow de Limites
.dropdown {
position: fixed;
position-anchor: --trigger;
/* Preferido: abaixo da âncora */
top: anchor(bottom);
left: anchor(left);
position-fallback: --dropdown-fallback;
}
@position-fallback --dropdown-fallback {
/* Fallback 1: acima da âncora */
@try {
bottom: anchor(top);
left: anchor(left);
}
/* Fallback 2: abaixo da âncora, alinhado à direita */
@try {
top: anchor(bottom);
right: anchor(right);
}
/* Fallback 3: acima da âncora, alinhado à direita */
@try {
bottom: anchor(top);
right: anchor(right);
}
}
Popover API: Camada de Popover Nativa
Uso Básico
<button popovertarget="my-popover">Abrir Popover</button>
<div id="my-popover" popover>
<p>Este é conteúdo de Popover nativo</p>
<button popovertarget="my-popover" popovertargetaction="hide">Fechar</button>
</div>
[popover] {
position: fixed;
inset: unset;
margin: 0;
padding: 16px;
border: 1px solid #e5e7eb;
border-radius: 8px;
background: white;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
}
Combinação Popover + Anchor
<button class="menu-trigger" popovertarget="menu-popover">Menu</button>
<div id="menu-popover" popover class="menu-dropdown">
<a href="/profile">Perfil</a>
<a href="/settings">Configurações</a>
<a href="/logout">Sair</a>
</div>
.menu-trigger {
anchor-name: --menu-anchor;
}
.menu-dropdown {
position-anchor: --menu-anchor;
position-area: bottom left;
margin: 4px;
}
anchor-size(): Auto-Dimensionamento Baseado no Elemento Âncora
.trigger {
anchor-name: --select-anchor;
}
.select-dropdown {
position: fixed;
position-anchor: --select-anchor;
top: anchor(bottom);
left: anchor(left);
/* Largura do dropdown segue o botão trigger */
width: anchor-size(width);
/* Ou definir largura mínima */
min-width: anchor-size(width);
}
Prática: Componentes UI Comuns em CSS Puro
Tooltip
<span class="tooltip-trigger" tabindex="0">
Ajuda
<span class="tooltip-content" role="tooltip">Este é um tooltip de ajuda</span>
</span>
.tooltip-trigger {
anchor-name: --tt-anchor;
position: relative;
cursor: help;
text-decoration: underline dotted;
}
.tooltip-content {
position: fixed;
position-anchor: --tt-anchor;
position-area: top center;
margin: 8px;
padding: 6px 10px;
background: #1f2937;
color: white;
border-radius: 4px;
font-size: 13px;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity 0.15s;
position-fallback: --tt-fallback;
}
.tooltip-trigger:hover .tooltip-content,
.tooltip-trigger:focus .tooltip-content {
opacity: 1;
}
@position-fallback --tt-fallback {
@try { position-area: bottom center; }
@try { position-area: center right; }
@try { position-area: center left; }
}
Menu Dropdown
<button class="dropdown-trigger" popovertarget="dd-menu">
Opções ▾
</button>
<div id="dd-menu" popover class="dropdown-menu">
<button class="dropdown-item">Editar</button>
<button class="dropdown-item">Copiar</button>
<button class="dropdown-item">Excluir</button>
</div>
.dropdown-trigger {
anchor-name: --dd-anchor;
}
.dropdown-menu {
position-anchor: --dd-anchor;
position-area: bottom left;
margin: 4px;
width: anchor-size(width);
min-width: 160px;
padding: 4px;
border-radius: 8px;
background: white;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
position-fallback: --dd-fallback;
}
.dropdown-item {
display: block;
width: 100%;
padding: 8px 12px;
border: none;
background: none;
text-align: left;
border-radius: 4px;
cursor: pointer;
}
.dropdown-item:hover {
background: #f3f4f6;
}
@position-fallback --dd-fallback {
@try { position-area: top left; }
}
Comparação com Floating UI/Popper.js
| Dimensão | CSS Anchor + Popover | Floating UI |
|---|---|---|
| Dependência JS | Zero JS | 12KB gzip |
| Desempenho | Nativo do navegador | Cálculo JS |
| Declarativo | Declarativo CSS | Imperativo JS |
| Flip de limites | position-fallback | middleware flip() |
| Offset | margin/anchor() | middleware offset() |
| Seta | Pseudo-elemento CSS | Elemento SVG/HTML |
| Elementos virtuais | Não suportado | Suportado |
| Conteúdo dinâmico | Auto-seguimento | Precisa de update() |
| Suporte de navegadores | Chrome 125+ | Todos os navegadores |
| Compatível com SSR | Totalmente compatível | Precisa de JS do cliente |
Quando Você Ainda Precisa de Bibliotecas JS
Cenários que ainda requerem Floating UI:
1. Precisa suportar navegadores antigos (Safari < 17.5, Firefox < 131)
2. Precisa de posicionamento de elemento virtual (seguimento do cursor)
3. Precisa de cadeias complexas de middleware (autoUpdate, size, hide)
4. Requisitos de wrapper declarativo para React/Vue
Cenários onde CSS Anchor funciona:
1. Tooltip, Dropdown, Popover e outros popups padrão
2. Precisa suportar apenas navegadores modernos
3. Buscando zero dependência JS
4. Cenários sensíveis a desempenho
Compatibilidade de Navegadores e Polyfill
Estado de Suporte
| Navegador | Anchor Positioning | Popover API |
|---|---|---|
| Chrome 125+ | ✅ | ✅ |
| Edge 125+ | ✅ | ✅ |
| Safari 17.5+ | ✅ | ✅ |
| Firefox 131+ | ✅ | ✅ |
| iOS Safari 17.5+ | ✅ | ✅ |
Soluções de Polyfill
<script src="https://cdn.jsdelivr.net/npm/@oddbird/css-anchor-positioning@0.3.0/dist/css-anchor-positioning.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@oddbird/popover-polyfill@0.4.0/dist/popover.min.js"></script>
Combinação com @starting-style para Animações de Popup
[popover] {
opacity: 0;
transform: translateY(-8px) scale(0.95);
transition: opacity 0.2s, transform 0.2s, display 0.2s allow-discrete;
overlay: none;
}
[popover]:popover-open {
opacity: 1;
transform: translateY(0) scale(1);
overlay: auto;
}
@starting-style {
[popover]:popover-open {
opacity: 0;
transform: translateY(-8px) scale(0.95);
}
}
Resumo
- CSS Anchor Positioning é a solução definitiva para posicionamento de popups — Zero JS, declarativo, nativo do navegador
- A Popover API torna o toggle de popups também zero JS — o atributo popovertarget resolve em uma linha
- position-fallback resolve o overflow de limites — Chega de cálculos JS para flip
- Todos os principais navegadores suportam em 2026 — Seguro para uso em produção
Após 10 anos, o posicionamento de popups finalmente voltou para onde pertence: o CSS. Isso não é uma melhoria incremental — é uma mudança de paradigma, assim como o Flexbox substituiu os layouts com float.
Experimente estas ferramentas executadas localmente no navegador — nenhum cadastro necessário →
#CSS锚点定位#Anchor Positioning#Popover API#弹出层#CSS