Anchor positioning
Lección 31 de 37 · 4 min
Un tooltip o un menú tiene que quedar pegado a su botón, y darse vuelta cuando no entra. Durante años eso pidió JavaScript que midiera posiciones; ahora lo resuelve CSS.
Anclar un elemento a otro
Anchor positioning es reciente: anda en Chrome y Edge desde 2024, en Safari 26 y en Firefox 147. Todavía hay navegadores sin soporte, así que usalo como mejora progresiva. Se arma con tres propiedades:
- El ancla
anchor-nameLe da al ancla un nombre que empieza con dos guiones, como--ancla. - A quién se pega
position-anchorVa en el elemento posicionado, que tiene que tenerposition: absoluteofixed: dice a qué ancla se pega. - Dónde cae
position-areaElige una zona de una grilla de 3×3 alrededor del ancla.topes toda la fila de arriba;top span-rightes arriba, desde el borde izquierdo del ancla hacia la derecha.
En el lienzo, el pin del comentario es el ancla y su nota es el elemento posicionado. Las líneas naranjas prolongan los bordes del ancla y arman la grilla de 3×3; la zona teñida es la que ocupa la nota. Elegí una posición, mové el pin con el slider y desplazá el lienzo (con la rueda, o con las flechas después de enfocarlo) para llevarlo a un borde.
bloque contenedor 288 × 208
Desplazá el lienzo hasta un borde
.pin {anchor-name: --pin;}.nota {/* sin soporte, queda en su posición estática */position: absolute;margin: 6px;}@supports (position-area: top) {.nota {position-anchor: --pin;position-area: top span-right;position-try-fallbacks: flip-block, flip-inline;}}
<button class="[anchor-name:--pin]" aria-describedby="comentario-3">Comentario 3</button><div id="comentario-3" role="tooltip"class="absolute m-1.5 [position-anchor:--pin] [position-area:top_span-right] [position-try-fallbacks:flip-block,flip-inline]">Más aire arriba</div>
También existe la función anchor(), que va en las propiedades de inset: top: anchor(bottom) pone el borde de arriba del tooltip sobre el borde de abajo del ancla. Sirve para ajustes finos, pero para el día a día preferí position-area: es más corta y los fallbacks la dan vuelta sin que tengas que pensar en cada lado.
Darse vuelta en el borde
Si el tooltip no entra en su zona, desborda el contenedor. position-try-fallbacks le da una lista de alternativas: cuando la posición actual desborda, el navegador prueba las opciones en orden y usa la primera que entra. Si ninguna entra, el tooltip desborda igual.
- De arriba a abajo
flip-blockLo da vuelta en el eje de bloque. - De izquierda a derecha
flip-inlineLo da vuelta en el eje inline. - Cambia los ejes
flip-startCambia un eje por el otro, asítoppasa aleftybottomaright.
Separadas por coma son opciones distintas; flip-block flip-inline sin coma es una sola opción que da vuelta los dos ejes. Para una alternativa a medida, definila con @position-try. Y anchor-size() mide el ancla: con ella, un menú nunca es más angosto que su botón.
@position-try --abajo-a-la-izquierda {position-area: bottom span-left;}@supports (position-area: top) {.menu {position-anchor: --boton;position-area: bottom span-right;position-try-fallbacks: --abajo-a-la-izquierda, flip-block;min-width: anchor-size(width);}}
El @supports deja afuera a los navegadores sin soporte: ahí el menú queda en su posición estática, donde estaría sin posicionar. Por eso conviene escribirlo justo después del botón en el HTML: así el fallback sigue teniendo sentido.
Con popover, para tooltips y menús
Anchor positioning decide dónde va el elemento, no cuándo aparece. Para eso está el atributo popover, Baseline desde 2025: pone el elemento en el top layer, por encima de todo y sin que lo recorte un overflow: hidden, y lo cierra con Escape o con un clic afuera. Juntos son la combinación recomendada para menús y tooltips.
<button popovertarget="opciones" class="boton">Opciones</button><div id="opciones" popover class="menu">…</div>
El navegador le da a todo popover margin: auto, que lo centraría dentro de su zona; ponele margin: 0 para que se alinee con el botón.
Anchor positioning es solo visual: no cambia el orden del DOM ni lo que anuncia un lector de pantalla. Dejá el tooltip cerca de su botón en el HTML, con role="tooltip", y conectalos con aria-describedby para que el botón lo lea como descripción. Si animás la entrada, hacelo dentro de @media (prefers-reduced-motion: no-preference).
En Tailwind
Tailwind v4.3 no trae utilidades para anchor positioning, así que van como propiedades arbitrarias: la propiedad y el valor entre corchetes, con guiones bajos en lugar de espacios. Las de inset y tamaño sí aceptan las funciones como valor arbitrario.
| CSS | Tailwind |
|---|---|
| anchor-name: --ancla | [anchor-name:--ancla] |
| position-area: top span-right | [position-area:top_span-right] |
| position-try-fallbacks: flip-block, flip-inline | [position-try-fallbacks:flip-block,flip-inline] |
| top: anchor(bottom) | top-[anchor(bottom)] |
| min-width: anchor-size(width) | min-w-[anchor-size(width)] |
| @supports (position-area: top) | supports-[position-area:top]: |
<button class="[anchor-name:--ancla]" aria-describedby="ayuda">Guardar</button><div id="ayuda" role="tooltip"class="absolute m-1 [position-anchor:--ancla] [position-area:top][position-try-fallbacks:flip-block,flip-inline]">Guarda sin cerrar</div>
Anchor positioning
Lesson 31 of 37 · 4 min
A tooltip or a menu has to stay attached to its button, and flip when it doesn't fit. For years that took JavaScript measuring positions; now CSS handles it.
Anchor one element to another
Anchor positioning is recent: it works in Chrome and Edge since 2024, in Safari 26 and in Firefox 147. Some browsers still lack it, so use it as a progressive enhancement. It takes three properties:
- The anchor
anchor-nameGives the anchor a name that starts with two dashes, like--anchor. - What it sticks to
position-anchorGoes on the positioned element, which needsposition: absoluteorfixed: says which anchor it sticks to. - Where it lands
position-areaPicks an area of a 3×3 grid around the anchor.topis the whole top row;top span-rightis above, from the anchor's left edge toward the right.
On the canvas, the comment pin is the anchor and its note is the positioned element. The orange lines extend the anchor's edges into the 3×3 grid; the tinted area is the one the note is using. Pick a position, move the pin with the slider and scroll the canvas (with the wheel, or with the arrow keys once it has focus) to bring it to an edge.
containing block 288 × 208
Scroll the canvas to an edge
.pin {anchor-name: --pin;}.note {/* without support, it stays at its static position */position: absolute;margin: 6px;}@supports (position-area: top) {.note {position-anchor: --pin;position-area: top span-right;position-try-fallbacks: flip-block, flip-inline;}}
<button class="[anchor-name:--pin]" aria-describedby="comment-3">Comment 3</button><div id="comment-3" role="tooltip"class="absolute m-1.5 [position-anchor:--pin] [position-area:top_span-right] [position-try-fallbacks:flip-block,flip-inline]">More air above</div>
There's also the anchor() function, which goes in the inset properties: top: anchor(bottom) puts the tooltip's top edge on the anchor's bottom edge. It's useful for fine tuning, but for everyday work prefer position-area: it's shorter, and the fallbacks flip it without you thinking about each side.
Flip at the edge
If the tooltip doesn't fit its area, it overflows the container. position-try-fallbacks gives it a list of alternatives: when the current position overflows, the browser tries the options in order and uses the first one that fits. If none fits, the tooltip overflows anyway.
- Top to bottom
flip-blockFlips it on the block axis. - Left to right
flip-inlineFlips it on the inline axis. - Swaps the axes
flip-startSwaps one axis for the other, sotopbecomesleftandbottombecomesright.
Separated by commas they are different options; flip-block flip-inline without a comma is a single option that flips both axes. For a custom alternative, define it with @position-try. And anchor-size() measures the anchor: with it, a menu is never narrower than its button.
@position-try --below-to-the-left {position-area: bottom span-left;}@supports (position-area: top) {.menu {position-anchor: --button;position-area: bottom span-right;position-try-fallbacks: --below-to-the-left, flip-block;min-width: anchor-size(width);}}
The @supports leaves out browsers without support: there the menu stays at its static position, where it would be without positioning. That's why it pays to write it right after the button in the HTML: the fallback still makes sense.
With popover, for tooltips and menus
Anchor positioning decides where the element goes, not when it shows up. That's what the popover attribute is for, Baseline since 2025: it puts the element in the top layer, above everything and safe from any overflow: hidden, and closes it with Escape or a click outside. Together they are the recommended combo for menus and tooltips.
<button popovertarget="options" class="button">Options</button><div id="options" popover class="menu">…</div>
The browser gives every popover margin: auto, which would center it inside its area; set margin: 0 so it lines up with the button.
Anchor positioning is visual only: it doesn't change the DOM order or what a screen reader announces. Keep the tooltip close to its button in the HTML, with role="tooltip", and connect them with aria-describedby so the button reads it as its description. If you animate the entrance, do it inside @media (prefers-reduced-motion: no-preference).
In Tailwind
Tailwind v4.3 ships no anchor positioning utilities, so they go in as arbitrary properties: the property and the value in brackets, with underscores instead of spaces. The inset and sizing utilities do take the functions as an arbitrary value.
| CSS | Tailwind |
|---|---|
| anchor-name: --anchor | [anchor-name:--anchor] |
| position-area: top span-right | [position-area:top_span-right] |
| position-try-fallbacks: flip-block, flip-inline | [position-try-fallbacks:flip-block,flip-inline] |
| top: anchor(bottom) | top-[anchor(bottom)] |
| min-width: anchor-size(width) | min-w-[anchor-size(width)] |
| @supports (position-area: top) | supports-[position-area:top]: |
<button class="[anchor-name:--anchor]" aria-describedby="help">Save</button><div id="help" role="tooltip"class="absolute m-1 [position-anchor:--anchor] [position-area:top][position-try-fallbacks:flip-block,flip-inline]">Saves without closing</div>
