CSS Anchor Position

Posicionamiento mediante anclajes


Desde hace mucho tiempo existen métodos de posicionamiento CSS, como posición relativa, posición absoluta y otros. Sin embargo, pueden resultar relativamente limitados en cuanto necesitamos un sistema de posicionamiento complejo. Recientemente se ha incorporado un mecanismo muy potente e interesante llamado Anchor Positioning (posicionamiento mediante anclajes), que es el que vamos a explicar en este artículo.

Este sistema se basa en que puedes «anclar elementos» respecto a otros. Para ello, tenemos que identificar dos elementos principales:

  • El elemento referencia (gris en el ejemplo), será nuestra ancla de referencia.
  • El elemento posicionado (rosa en el ejemplo) respecto al elemento anterior.

La compatibilidad de Anchor Position en navegadores es la siguiente:

Posicionar elementos con anclajes

Para posicionar utilizando Anchor Position debemos conocer la propiedad anchor-name. Con ella, definimos el nombre del ancla utilizada para definir un elemento de referencia. Pero antes, examinemos el siguiente ejemplo, donde aún no utilizamos Anchor Position, pero preparamos un ejemplo para comenzar a utilizarlo:

body {
  font-family: Jost, sans-serif;
  color: #fff;
  text-align: center;
}

.reference {
  max-width: 150px;
  margin: auto;
  margin-top: 4rem;
  background: #444;
}

.element {
  max-width: 75px;
  background: deeppink;
  font-size: 0.9rem;
  margin: 0;
}
<div class="reference">Elemento de referencia</div>
<div class="element">Elemento a posicionar</div>

Como ves, por defecto, los elemento se colocan según aparecen en el HTML. Como he indicado unos márgenes para el elemento gris, se ve centrado en pantalla, sin embargo el elemento rosa aparece a continuación porque es la parte donde sigue el orden del HTML.

La propiedad anchor-name nos permitirá definir un elemento de referencia, dándole un nombre (en mi caso he usado --first-box). Este nombre debe prefijarse de --, como las variables CSS, sin embargo no usaremos la función var().

Por otro lado, la propiedad position-anchor permite posicionar otro elemento respecto a este primer elemento de referencia, indicándole el nombre de ancla que se define mediante anchor-name.

Propiedad Descripción
anchor-name Declara un elemento como ancla de referencia que permitirá posicionar otros elementos.
position-anchor Posicionamos el elemento mediante el ancla de referencia indicado.

Ahora sí, al código CSS mostrado en el ejemplo anterior, vamos a añadir el siguiente código donde utilizaremos estas dos propiedades y la función anchor():

.reference {
  anchor-name: --first-box;   /* Creamos referencia */
}

.element {
  position: absolute;
  position-anchor: --first-box; /* Acoplamos a referencia */
  bottom: anchor(top);
  left: anchor(left);
}
<div class="reference">Elemento de referencia</div>
<div class="element">Elemento a posicionar</div>

¿Qué es lo que hemos hecho? Analicemos paso a paso:

  • 1️⃣ Antes de nada, hemos creado un elemento de referencia con anchor-name. Se llama --first-box.
  • 2️⃣ Luego, hemos posicionado otro elemento, que debe estar posicionado con absolute.
  • 3️⃣ Por último, hemos indicado a que elemento lo anclamos. Eso lo haremos con position-anchor.

Con estos sencillos pasos, ya tenemos esos dos elementos «anclados». Ahora sólo nos falta establecer la colocación de uno respecto al otro, que es lo que hacemos mediante la función anchor() en las dos últimas líneas. Lo explicaremos en el siguiente apartado.

La función anchor()

La función anchor() nos permite indicar como se posiciona un elemento respecto a su elemento de referencia. En el ejemplo anterior lo hemos hecho de forma implícita, mediante las propiedades bottom, left, right o top.

  • 1️⃣ Las propiedades bottom, left, right o top indican la parte del elemento posicionado (rosa).
  • 2️⃣ El parámetro de la función anchor() indica la parte del elemento de referencia (gris) a usar.

En nuestro ejemplo, hemos utilizado las propiedades bottom: anchor(top) y left: anchor(left), es decir, queremos que el elemento a posicionar (rosa) se conecte desde su bottom a la parte superior de la referencia (gris) y desde su izquierda (rosa) a la parte izquierda de la referencia (gris).

Si no te queda claro, puedes jugar un poco con estos valores:

.reference {
  anchor-name: --first-box;
}

.element {
  position: absolute;
  position-anchor: --first-box;
  bottom: anchor(top);
  left: anchor(left);
}
<section>
  <div class="options">
    <label>
      Propiedad <strong>left</strong>:
      <select data-property="left">
        <option>-ninguno-</option>
        <option selected>anchor(left)</option>
        <option>anchor(right)</option>
      </select>
    </label>
    <label>
      Propiedad <strong>right</strong>:
      <select data-property="right">
        <option selected>-ninguno-</option>
        <option>anchor(left)</option>
        <option>anchor(right)</option>
      </select>
    </label>
    <label>
      Propiedad <strong>top</strong>:
      <select data-property="top">
        <option selected>-ninguno-</option>
        <option>anchor(top)</option>
        <option>anchor(bottom)</option>
      </select>
    </label>
    <label>
      Propiedad <strong>bottom</strong>:
      <select data-property="bottom">
        <option>-ninguno-</option>
        <option selected>anchor(top)</option>
        <option>anchor(bottom)</option>
      </select>
    </label>
  </div>
</section>
<section>
  <div class="reference">Elemento de referencia</div>
  <div class="element">Elemento a posicionar</div>
</section>
const selectOptions = [...document.querySelectorAll(".options select")];
const element = document.querySelector(".element");
selectOptions.forEach(select => select.addEventListener("input", (ev) => {
  const prop = select.dataset.property;
  const value = select.options[select.selectedIndex] === "-ninguno-"
    ? "auto"
    : select.options[select.selectedIndex].value;
  element.style.setProperty(`--${prop}`, value);
}));

Jugando un poco con los valores de cada propiedad left, right, top y bottom podrás comprobar como funciona la función anchor().

Referencias explícitas

La función anchor() también se puede utilizar de una forma un poco más directa, indicando dos parámetros: el elemento de referencia (siempre prefijado por --) y el lugar a posicionar:

.element {
  position: absolute;
  bottom: anchor(--first-box top);
  left: anchor(--first-box left);
}

De esta forma, esa relación queda más clara, y es bastante útil si vamos a realizar referencias desde distintas anclas, de modo que queda mucho más legible.

La función anchor-size()

Además de la función anchor(), también disponemos de la función anchor-size(). Con esta función podemos indicar a nuestro elemento posicionado (rosa) el tamaño que tenemos en nuestro elemento de referencia (gris) o valores relacionados.

.element {
  position: absolute;
  bottom: anchor(--first-box top);
  left: anchor(--first-box left);
  width: calc(anchor-size(width) * 2);
  height: calc(anchor-size(height) * 0.5);
}

El ejemplo de código, hemos establecido para el elemento .element un tamaño de ancho con la propiedad width. En su valor, hemos calculado el ancho del elemento de referencia con anchor-size(width) y lo hemos duplicado con calc(... * 2).

De la misma forma, hemos utilizado la propiedad height para utilizar la mitad del tamaño de alto del elemento de referencia.

La función anchor-size() nos permite utilizar varias palabras clave por parámetro:

Valor Descripción
width Ancho del elemento de referencia.
height Alto del elemento de referencia.
block Versión lógica del modo de escritura del contenedor del elemento de referencia.
inline Versión lógica del modo de escritura del contenedor del elemento de referencia.
self-block Versión lógica del modo de escritura del elemento de referencia.
self-inline Versión lógica del modo de escritura del elemento de referencia.

Áreas de inserción

Además de la forma anterior de posicionar elementos, tenemos la propiedad inset-area que nos proporciona una forma quizás más clara y directa de posicionar elementos, donde no necesitamos preocuparnos más que de la parte desde donde se va a conectar un elemento con otro.

Propiedad Descripción
inset-area Establece el área donde vamos a conectar el elemento.

La propiedad inset-area permite utilizar una gran cantidad de valores clave como los de la tabla siguiente:

Valor Descripción
Básicos Posiciona el elemento en una orientación left, center, right, top o bottom.
span-* Deja el máximo espacio posible en la orientación indicada, colocandolo al otro extremo.
x-* | y-* Coloca el elemento hacia el lado contrario del eje indicado.
span-x-* | span-y-* Coloca el elemento hacia dentro del eje indicado.
x-self-* | y-self-* Similar a x-* o y-*, sobre si mismo.
span-x-self-* | span-y-self-* Similar a span-x-* o span-y-*, sobre si mismo.
span-all Posiciona el elemento en todos los ejes hacia dentro, generalmente resultando centrado.

Puedes observar un ejemplo del funcionamiento de estos valores en el siguiente ejemplo interactivo:

.reference {
  anchor-name: --first-box;
}

.element {
  position: absolute;
  position-anchor: --first-box;
  inset-area: top;
}
<label>
  Propiedad <strong>inset-area</strong>:
  <select>
    <optgroup label="basic">
      <option>top</option>
      <option>left</option>
      <option>center</option>
      <option>right</option>
      <option>bottom</option>
    </optgroup>

    <optgroup label="span-">
      <option>span-left</option>
      <option>span-right</option>
      <option>span-top</option>
      <option>span-bottom</option>
      <option>span-all</option>
    </optgroup>

    <optgroup label="x-">
      <option>x-start</option>
      <option>x-end</option>
      <option>y-start</option>
      <option>y-end</option>
    </optgroup>

    <optgroup label="span-x-">
      <option>span-x-start</option>
      <option>span-x-end</option>
      <option>span-y-start</option>
      <option>span-y-end</option>
    </optgroup>

    <optgroup label="x-self-">
      <option>x-self-start</option>
      <option>x-self-end</option>
      <option>y-self-start</option>
      <option>y-self-end</option>
    </optgroup>

    <optgroup label="span-x-">
      <option>span-x-self-start</option>
      <option>span-x-self-end</option>
      <option>span-y-self-start</option>
      <option>span-y-self-end</option>
    </optgroup>
  </select>
</label>
<div class="reference">Elemento de referencia</div>
<div class="element">Elemento a posicionar</div>
const selectOptions = document.querySelector("select");
const element = document.querySelector(".element");
selectOptions.addEventListener("input", (ev) => {
  const value = selectOptions.options[selectOptions.selectedIndex].value;
  element.style.setProperty(`--inset-area`, value);
});

Además, la propiedad inset-area también permite combinarlos en algunas situaciones, o hacer uso de propiedades lógicas como block-start, span-block-end, inline-start o span-inline-end entre muchas otras.

El valor anchor-center

Es posible que en algunas situaciones, necesitemos centrar el elemento respecto al elemento de referencia. Para ello, podemos utilizar el valor anchor-center en propiedades como justify-self, align-self, justify-items o align-items.

.reference {
  anchor-name: --first-box;
}

.element {
  position: absolute;
  position-anchor: --first-box;
  inset-area: top;
  align-self: anchor-center;
}

En ciertas situaciones nos puede venir bastante bien poder apoyarnos en este tipo de centrado adicional. Obviamente, es necesario tener el elemento posicionado respecto a un ancla de referencia.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev