anchor-name y position-anchor: atar dos elementos
Cómo se declara un ancla, cómo se apunta a ella, qué relación de árbol exige la especificación, y el ancla implícita que te dan popovertarget y commandfor.
Durante veinte años, colocar un tooltip junto a su botón exigió JavaScript: medir el botón, medir la ventana, calcular la posición, escribirla en el estilo, y volver a hacerlo en cada scroll y en cada cambio de tamaño. Bibliotecas enteras existen para eso. El posicionamiento por anclas mueve el cálculo al motor de layout, donde ya estaba toda la información, y lo hace con dos propiedades: una que da nombre a un elemento y otra que apunta a ese nombre.
- Declarar un ancla con
anchor-namey consumirla conposition-anchor. - Explicar la relación de árbol que la especificación exige entre ancla y anclado.
- Acotar nombres repetidos con
anchor-scope. - Aprovechar el ancla implícita de
popovertargetycommandfor.
Las dos propiedades
anchor-name da a un elemento uno o varios nombres, escritos como identificadores con guion doble, igual que las custom properties.
.boton-opciones { anchor-name: --opciones; }
position-anchor declara, en un elemento posicionado, cuál es su ancla por defecto.
.menu-opciones {
position: absolute; /* o fixed */
position-anchor: --opciones;
}
Con eso, el .menu-opciones ya sabe respecto a qué elemento colocarse, pero todavía no se ha movido: falta decirle cómo, que es la función anchor() de la siguiente lección, o position-area, que veremos después.
Tres requisitos que hay que cumplir para que la relación exista:
El elemento anclado tiene que estar posicionado en absoluto o en fijo. Un relative o un static no pueden consumir un ancla. Es coherente: el anclaje sustituye a la resolución normal de los desplazamientos, que solo tienen efecto en elementos fuera de flujo.
El ancla tiene que ser válida respecto al anclado. La especificación exige que el ancla sea un elemento del mismo documento cuyo bloque contenedor no dependa del anclado, y en la práctica esto significa que el ancla debe ser el anclado mismo, un antepasado suyo, o un elemento que aparezca antes en el orden del árbol de cajas. No puedes anclarte a un elemento que va después.
Los dos tienen que estar en el mismo árbol o en un árbol accesible. Un nombre declarado dentro de un shadow DOM no es visible desde fuera por defecto.
Un elemento puede declarar varios nombres —anchor-name: --menu, --tooltip— y varios elementos anclados pueden apuntar al mismo nombre. Si dos elementos comparten nombre, gana el último en el orden del árbol.
anchor-scope y los nombres repetidos
El problema aparece en cuanto el patrón se usa dentro de una lista. Si cada fila de una tabla declara anchor-name: --fila para su propio menú, todas las filas comparten el nombre y todos los menús se anclan a la última.
anchor-scope acota la visibilidad de un nombre a un subárbol, igual que un ámbito léxico.
.fila {
anchor-scope: --fila; /* el nombre --fila solo existe dentro de esta fila */
}
.fila .disparador { anchor-name: --fila; }
.fila .menu { position: absolute; position-anchor: --fila; }
Con esa declaración, cada .fila es una frontera: el --fila de dentro no se ve desde otras filas y cada menú encuentra el suyo. anchor-scope: all acota todos los nombres declarados en el subárbol, que es lo que quieres cuando el componente es una caja negra reutilizable.
anchor-scope está en los tres motores: Chrome 131, Safari 26 y Firefox 147.
El ancla implícita
Hay un caso que no necesita ni anchor-name ni position-anchor. Cuando un botón abre un popover con el atributo popovertarget, o invoca un elemento con commandfor, el HTML establece una relación de ancla implícita: el botón es automáticamente el ancla del elemento que abre.
<button popovertarget="menu">Opciones</button>
<div id="menu" popover>...</div>
#menu {
position-anchor: auto; /* usa el ancla implícita */
position-area: block-end span-inline-end;
margin-block-start: .5rem;
}
El valor auto de position-anchor significa exactamente eso: usa el ancla implícita si la hay. Es el patrón más corto que existe para un menú anclado, y no tiene una sola línea de JavaScript.
El ancla implícita vía popovertarget está en Chrome 133, Safari 26 y Firefox 147. La vía commandfor llegó en Chrome 135, Safari 26.2 y Firefox 147.
flowchart TB
A[Quieres anclar un elemento a otro] --> B{El anclado se abre desde un boton}
B -->|Si, con popovertarget o commandfor| C[Ancla implicita]
C --> D[position-anchor auto y nada mas]
B -->|No| E[anchor-name en el ancla]
E --> F[position-anchor con ese nombre en el anclado]
F --> G{El nombre se repite en una lista}
G -->|Si| H[anchor-scope en el contenedor de cada elemento]
G -->|No| I[Listo, ahora define como se coloca]
H --> I
style A fill:#89b4fa,color:#11111b
style C fill:#a6e3a1,color:#11111b
style D fill:#a6e3a1,color:#11111b
style H fill:#cba6f7,color:#11111b
style I fill:#a6e3a1,color:#11111bEl estado del soporte, con precisión
Conviene ser exacto porque circulan varias versiones de esta historia.
El posicionamiento por anclas llegó primero a Chrome 125, en mayo de 2024. Safari 26 lo implementó en septiembre de 2025, con lo que entró en dos motores. Firefox 147 lo activó por defecto en enero de 2026, y con eso la función pasó a estar en los tres. Es Baseline recién disponible.
Las piezas centrales —anchor-name, position-anchor, anchor(), anchor-size(), position-area, @position-try, position-try-fallbacks— comparten exactamente esas tres versiones. No hay ninguna que esté en unos motores y no en otros dentro de ese conjunto.
Hay una excepción, y es position-visibility: Chrome 125 y Firefox 147, pero Safari 26.2, no 26. Y sus valores han cambiado de nombre por el camino, cosa que trataremos en la última lección del nivel.
Dicho de otro modo: si tu base de usuarios está en versiones de 2026, puedes usar anclas. Si tienes que soportar Safari 18 o Firefox 146, necesitas un plan de degradación, y hay uno bueno.
La razón de fondo por la que el anclaje entró en el lenguaje no es la comodidad, es que una biblioteca de posicionamiento no puede ser correcta. Piensa en lo que hace: lee la geometría del ancla con getBoundingClientRect(), calcula una posición y la escribe en el estilo del anclado. Ese ciclo ocurre necesariamente después del layout, porque la lectura lo requiere, y provoca un segundo layout, porque la escritura lo invalida. Con eso ya tienes dos problemas estructurales: el anclado va siempre un fotograma por detrás del ancla, lo que se ve como un temblor al hacer scroll rápido o al arrastrar; y cada actualización cuesta dos pasadas de layout en lugar de una. Y hay un tercero peor: hay situaciones en las que el bucle no converge, porque colocar el anclado cambia la geometría de la página, lo que cambia la posición del ancla, lo que exige recolocar el anclado. Las bibliotecas serias lo resuelven con heurísticas, límites de iteración y contención del scroll, es decir, aproximándose. Al mover el cálculo dentro del motor de layout, la posición del anclado se resuelve en la misma pasada que la del ancla, no un fotograma después, y la especificación define reglas de validez que impiden por construcción las dependencias circulares —esa es la razón real de la regla de que el ancla debe preceder al anclado en el árbol—. No es una versión más cómoda de lo que ya hacías: es la versión que puede ser correcta.
- Declara un
anchor-nameen un botón y unposition-anchoren un div absoluto, y comprueba en DevTools que la relación existe aunque el div todavía no se mueva. - Repite el patrón en una lista de cinco filas sin
anchor-scopey observa que todos los menús se van a la última. - Arréglalo con
anchor-scopeen el contenedor de cada fila. - Monta la versión con
popovertargetyposition-anchor: autoy comprueba que funciona sin nombres. - Intenta anclar un elemento a otro que aparece después en el árbol y comprueba qué ocurre.