Posicionamiento del anclaje

Cuando colocas una sugerencia o un menú desplegable, a menudo quieres posicionarlo en relación con otro elemento de la página. Si bien existen formas de lograr este efecto con el posicionamiento absoluto, históricamente los requisitos más complejos recurrieron al posicionamiento de elementos con JavaScript.

El posicionamiento de anclaje de CSS proporciona una forma de posicionar de forma declarativa un elemento en relación con otro.

Elementos de amarre

Para convertir un elemento en un ancla, asígnale un valor anchor-name de cualquier cadena que comience con dos guiones. Este es el identificador que usará el elemento posicionado para encontrar su ancla, y es útil darle un nombre descriptivo. Incluso puedes asignar varios nombres de anclaje a un elemento si se usará como anclaje de diferentes maneras.

Deberás establecer algunas propiedades en el elemento posicionado para que se pueda vincular. Primero, debes sacar el elemento del flujo del documento para que flote. Para ello, configura position: absolute o position: fixed.

A continuación, deberás establecer a qué ancla deseas vincular el objeto estableciendo position-anchor en el nombre del ancla que estableciste en el ancla.

Por último, deberás establecer la posición del ancla. Obtendrás más información sobre position-area más adelante en este módulo.

#anchor {
   anchor-name: --my-anchor;
}

#positionedElement {
     position: absolute;
     position-anchor: --my-anchor;
     position-area: end;
}

Amarres implícitos

Los elementos emergentes son aún más fáciles de vincular. Cuando abres una ventana emergente con un botón que tiene un popovertarget o cuando configuras un source con showPopover({source}), la ventana emergente ya tiene un "anclaje implícito" establecido. Dado que, de forma predeterminada, un elemento emergente ya flota con position: fixed, para posicionarlo, solo debes establecer la posición.

#anchor{}

#positionedElement {
  position-area: end;
  margin: unset;
}

Cómo definir el alcance de los posibles anclajes

Puedes implementar el posicionamiento de anclaje como parte de un componente, de modo que puedas usar un patrón como un menú desplegable en varios lugares. Si usas el mismo anchor-name varias veces, ¿cómo te aseguras de que cada elemento posicionado encuentre el anclaje correcto?

Las soluciones de JavaScript implican agregar IDs únicos a cada ancla y, luego, hacer referencia a ellos desde el elemento posicionado. Esto se vuelve engorroso, y CSS tiene una solución más simple con anchor-scope.

La propiedad anchor-scope establece qué nombres de anclaje se compararán solo entre un elemento y sus elementos secundarios. Acepta una lista de uno o más nombres de anclaje o la palabra clave all para limitar el alcance de todos los nombres de anclaje definidos.

Lo ideal es agregar un anchor-scope a un elemento superior tanto del elemento posicionado como del elemento de anclaje que no contenga otros elementos de anclaje con el mismo nombre. A menudo, se encuentra en la raíz del componente reutilizable.

En el siguiente ejemplo, se muestra la diferencia que genera anchor-scope cuando se aplica a elementos repetidos con el mismo anchor-name. En el ejemplo, todos los elementos <img> y los banners de imágenes hacen referencia al nombre de anclaje --image. Cuando se aplica anchor-scope a los elementos <li>, position-anchor: --image solo coincidirá con el elemento <img> dentro del mismo elemento <li> que el banner. De lo contrario, coincidirá con el último elemento <img> renderizado.

Posicionamiento

Ahora que ya uniste el elemento a tu ancla, es momento de posicionarlo. El posicionamiento de anclaje proporciona dos métodos de posicionamiento: position-area y la función anchor().

position-area

La propiedad position-area te permite posicionar un elemento alrededor del ancla especificando una o dos palabras clave. Esto abarca muchos casos de uso comunes y, a menudo, es un buen punto de partida.

Cómo funciona position-area

position-area funciona creando un nuevo bloque contenedor para el elemento posicionado en un área generada por los bordes del ancla y el bloque contenedor original del elemento posicionado.

Si bien hay muchas palabras clave disponibles para position-area, se pueden dividir en algunas categorías para que sean más fáciles de comprender. Anchor-tool.com es una excelente herramienta para explorar la sintaxis.

Palabras clave físicas

Puedes usar las palabras clave físicas top, left, bottom, right y center. Por ejemplo, position-area: top right colocará el elemento posicionado arriba y a la derecha del elemento de anclaje. Estas palabras clave también tienen equivalentes de ejes físicos: y-start, x-start, y-end y x-end.

Palabras clave lógicas

También puedes usar palabras clave lógicas, block-start, block-end, inline-start y inline-end. Por ejemplo, position-area: block-end inline-start colocará el elemento posicionado debajo y a la izquierda del elemento de anclaje en idiomas como el inglés, o después del elemento de anclaje en el eje de bloque y antes del elemento de anclaje en el eje intercalado en el modo de escritura del documento. center también se puede usar con una palabra clave lógica.

También puedes omitir el eje si especificas palabras clave lógicas, con el eje de bloqueo primero y el eje intercalado segundo. position-area: start end es lo mismo que position-area: block-start inline-end o incluso position-area: inline-end block-start.

Abarca varias áreas de la cuadrícula

Hasta ahora, es posible que hayas notado que estas opciones solo te permiten colocar el elemento posicionado dentro de un solo espacio de cuadrícula. Agregar el prefijo span a las propiedades físicas o lógicas agrega el espacio de la cuadrícula central adyacente. position-area: span-top right se posicionará a la derecha del ancla y desde la parte inferior del ancla hasta la parte superior del bloque contenedor original del elemento posicionado.

Una posición y un área comunes para un menú desplegable son position-area: block-end span-inline-end.

La palabra clave span-all abarca 3 filas o columnas.

Palabra clave única

Si solo estableces una palabra clave, el otro eje se configurará automáticamente. En gran medida, funciona como esperarías, pero puede ser útil comprender cómo funciona.

Si la palabra clave proporcionada es clara sobre su eje, el otro eje se calcula como span-all. Esto significa que position-area: bottom es equivalente a position-area: bottom span-all, y el elemento posicionado estará debajo del elemento de anclaje y tendrá disponible todo el ancho del bloque contenedor.

Por otro lado, si la palabra clave no indica claramente un eje, se repite. position-area: start es equivalente a start start y se coloca en la parte superior izquierda del anclaje en los idiomas que se leen de izquierda a derecha.

La función anchor()

Para casos de uso más avanzados, es posible que position-area no cumpla con tus requisitos. La función anchor() te permite establecer propiedades de inserción individuales según la posición de otro elemento. Esto se resuelve en una longitud de CSS, lo que significa que puedes usarla en cálculos y con otras funciones de CSS. Además, también puedes unir diferentes lados a diferentes anclajes.

La función anchor() toma un nombre de anclaje y un lado de anclaje. Si tu elemento tiene un anclaje predeterminado, ya sea establecido con position-anchor o de forma implícita, por ejemplo, con un elemento emergente, puedes omitir el nombre del anclaje.

.positionedElement {
  block-start: anchor(--my-anchor start);
  /*  OR  */
  position-anchor: --my-anchor;
  block-start: anchor(start);
}

Valores de resguardo

Si no se puede encontrar un anclaje para una función anchor(), toda la declaración no será válida. Esto puede suceder si el ancla se renderiza después del elemento posicionado o si no hay un elemento con un anchor-name coincidente. Para controlar esto, puedes establecer una duración o un porcentaje de resguardo.

.positionedElement {
   block-start: anchor(--my-anchor, 100px)
}

En el ejemplo anterior, el valor izquierdo del elemento posicionado está anclado a --focused-anchor, pero ese anchor-name solo existe cuando se coloca el cursor sobre el primer botón o se enfoca en él. Dado que una función anchor() se resuelve en una longitud, puedes usar otro anclaje como alternativa. Si no proporcionamos una alternativa, el elemento posicionado no se posicionaría.

Palabras clave de la posición lateral del ancla

El valor del lado de anclaje elige contra cuál de los bordes del anclaje se posicionará. De manera similar a position-area, el valor del lado de anclaje admite varios tipos diferentes de sintaxis.

Tipo Valores Descripción
Físico top, left, bottom, right

Las palabras clave físicas corresponden a un lado específico del anclaje, pero solo se pueden usar en el mismo eje que la inserción del elemento posicionado que estás configurando.

Por ejemplo, top: anchor(bottom) posiciona la parte superior del elemento en la parte inferior del ancla, pero left: anchor(top) no funcionará.

Margen inside, outside

La palabra clave inside corresponde al mismo lado que la propiedad de inserción, y la palabra clave outside corresponde al lado opuesto en el mismo eje.

Por ejemplo, inset-block-start: anchor(inside) hace referencia al lado block-start del anclaje, y inset-inline-end: (outside) hace referencia al lado inline-start del anclaje.

Lógico start, end, self-start, self-end

Las palabras clave lógicas hacen referencia a los lados del ancla según el modo de escritura del elemento posicionado con self-start y self-end, o bien con el modo de escritura del bloque contenedor del elemento posicionado con start y end.

Porcentaje 0% a 100%

Un valor de porcentaje coloca el elemento posicionado a lo largo del eje desde el inicio hasta el final del anclaje en el eje especificado. 0% está en el lado start del ancla, y 100% es el lado final del ancla. center es equivalente a 50%. Si usas un porcentaje en una inserción del lado final, como bottom, esto no se invierte: 0% sigue siendo el lado start del ancla.

En este ejemplo, se muestra cómo un valor de porcentaje siempre va del inicio al final en el eje especificado:

Usa anchor()

Como anchor() es una longitud, es muy flexible. Puedes manipular el valor con funciones de CSS como max() y calc().

Una limitación es que solo puedes usar funciones anchor() en propiedades de inserción.

En el ejemplo anterior, se agrega un fondo detrás del panel de detalles abierto que se anima de forma fluida cuando se abre un panel diferente y se estira para incluir un panel de detalles sobre el que se coloca el cursor. Para lograrlo, usa min() para elegir la longitud más corta entre dos anclajes.

#indicator{
/*  Use the smaller of the 2 values:  */
  inset-block-start: min(
/*   1. The start side of the default anchor, which is the open `<details>` element  */
    anchor(start),
/*   2. The start side of the hovered `<details>` element.    */
    anchor(--hovered start,
/*     If no `<details>` element is hovered, this falls back to infinity px, so that the other value is smaller, and therefore used.   */
       var(calc(1px * infinity)))
  );
}

En el ejemplo, también se usa calc() para agregar espacio intercalado alrededor del panel abierto.

Cómo usar el tamaño del ancla

También puedes usar la función anchor-size() para usar las dimensiones del anclaje para el tamaño, la posición o el margen de tu elemento posicionado.

anchor-size() toma un nombre de anclaje o usa el anclaje predeterminado. De forma predeterminada, usará el tamaño del anclaje en el eje en el que se usa, por lo que width: anchor-size() devolverá el ancho del anclaje. También puedes usar el otro eje especificando la longitud que desees, con las palabras clave físicas width y height, o las palabras clave lógicas block, inline, self-block y self-inline.

Cómo controlar el desbordamiento

Creaste un componente de menú desplegable y usaste el posicionamiento de anclaje para colocarlo donde querías. Sin embargo, luego moviste el menú al otro lado de la pantalla o lo usaste para un menú de usuario, y el nombre del usuario es muy largo. De repente, el menú desplegable desaparece de la pantalla. ¿Qué sigue?

El posicionamiento de anclaje de CSS tiene un sistema integrado que te permite crear rápidamente un conjunto sólido de alternativas cuando el elemento posicionado termina fuera de su bloque contenedor.

Opciones de resguardo

La regla position-try-fallbacks toma una lista de opciones de resguardo. Cuando la posición predeterminada se desborda, se probará cada opción en orden hasta que haya una posición que no se desborde.

Puedes usar cualquier valor de position-area como opción de resguardo. En este ejemplo, en los modos de escritura de izquierda a derecha, como el inglés, el elemento posicionado intentará ubicarse en la parte inferior del elemento de anclaje, abarcando las columnas central y derecha. Si se desborda, intentará posicionarse en la parte inferior del elemento de anclaje y abarcará las columnas izquierda y central. Si también se desborda, la posición volverá a la posición predeterminada, aunque también se desborde.

.positioned-element {
  position-area: block-end span-inline-end;
  position-try-fallbacks: block-end span-inline-start;
}

También hay varias palabras clave de flip- que controlan casos de resguardo comunes. flip-block y flip-inline intentan voltear el elemento sobre los ejes de bloque y en línea. También se pueden combinar con flip-block flip-inline para invertir ambos ejes. El valor flip-start voltea el elemento posicionado sobre una línea diagonal desde las esquinas inicial y final del elemento de anclaje.

También puedes crear una opción de resguardo personalizada con @position-try, lo que te permite establecer los márgenes, la alineación y hasta cambiar el anclaje.

@position-try --menu-below {
  position-area: bottom span-right;
  margin-top: 1em;
}

#positioned-element {
  position-try: --menu-below;
}

Se pueden agregar flip-block y flip-inline a las opciones de resguardo de @position-try para crear una variante.

#positioned-element {
  position-try: --menu-below, flip-inline --menu-below;
}

En el ejemplo anterior, el navegador sigue estos pasos y se detiene en cuanto encuentra una solución que no desborda.

  1. El elemento se coloca con position-area: end, en la parte inferior derecha del ancla.
  2. Si se desborda, el elemento se coloca con la opción de resguardo personalizada llamada --bottom-span-right, que lo coloca con position-area: bottom span-right, con un margen adicional debajo.
  3. Si se desborda, el elemento se coloca con flip-inline --bottom-span-right, que combina la opción de resguardo personalizada con flip-inline, que es esencialmente position-area: bottom span-left.
  4. Si se desborda, el elemento se coloca con la opción de resguardo personalizada --use-alternate, que lo coloca debajo de un anclaje completamente diferente.
  5. Si se desborda, el elemento vuelve a su ubicación original, con position-area: end, aunque se sabe que se desborda.

Pedido de resguardo

De forma predeterminada, cuando la posición inicial se desborda, el navegador probará cada opción en position-try-fallbacks hasta que encuentre una posición que no se desborde. Puedes anular este comportamiento con position-try-order para probar cada opción de resguardo y usar la que tenga más espacio en un eje especificado.

Puedes especificar el eje con las palabras clave lógicas, most-block-size y most-inline-size, o con las palabras clave físicas most-height y most-width.

position-try-order y position-try-fallbacks se pueden combinar con la abreviatura position-try, y el orden se indica primero.

Desplazamiento

Cuando un usuario se desplaza, espera que la página se mueva con fluidez. Para lograr esto, los navegadores tienen límites sobre cómo se puede usar el posicionamiento de anclaje durante el desplazamiento.

Si bien puedes vincular un elemento posicionado a anclajes en diferentes contenedores de desplazamiento, el elemento solo se moverá en respuesta al desplazamiento de uno de los anclajes. Este será el anclaje predeterminado, que puede ser el anclaje implícito de una ventana emergente o el valor de position-anchor.

Observarás que el elemento posicionado permanece visible incluso cuando el elemento de anclaje se desplaza fuera de la vista. Para ocultar el elemento posicionado cuando se oculta el elemento de anclaje, establece position-visibility: anchors-visible. Esto no solo se aplica cuando se desplaza en exceso el ancla, sino también si se oculta de otras maneras, por ejemplo, con visibility: hidden.

Verifica tus conocimientos

¿Cuáles son los valores válidos para el lado en anchor()?

inside
Correcto.
25%
Correcto.
25px
Incorrecto. Si bien se puede usar una longitud como 25px como valor de resguardo, solo se pueden usar porcentajes para el lado.
block-start
Incorrecto
start
Correcto.

¿Cuáles son los valores válidos para position-area?

top
Correcto.
block-end inline-end
Correcto.
block-start block-end
Incorrecto. Solo puedes definir una sola columna o fila en cada eje.

¿Qué propiedades admiten la función anchor()?

top
Correcto.
margin-left
Incorrecto.
inset-block-start
Correcto.
transform
Incorrecto.

¿Qué sucede si hay varios anclajes con el mismo anchor-name?

El elemento posicionado se duplica y se une a cada coincidencia.
Incorrecto.
El elemento posicionado está unido al primero del documento.
Incorrecto.
El elemento posicionado está vinculado al último elemento del documento.
Correcto.
El elemento posicionado se une al ancla más cercana.
Incorrecto.