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 los ejemplos), será nuestra ancla de referencia.
- El elemento posicionado (rosa en los ejemplos) respecto al elemento anterior.
Pero antes, vamos a explicar los pilares básicos.
Posicionamiento mediante anclajes
Para entender como posicionar con esta nueva técnica, mediante anclajes, es necesario conocer varias propiedades CSS principales:
- 1️⃣
anchor-name
: Define nombre a un elemento para usarlo como punto de anclaje y posicionar otros. - 2️⃣
anchor-scope
: Limita que puntos de anclaje son visibles y desde donde (evitar duplicados). - 3️⃣
position-anchor
: Desde un elemento posicionado, indica a que punto de anclaje se va a referir por defecto.
Vamos a analizarlas.
La propiedad anchor-name
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:
.reference {
max-width: 150px;
margin: auto;
margin-top: 4rem;
padding: 0.5rem;
background: #444;
anchor-name: --first-box; /* Creamos referencia */
}
.element {
max-width: 75px;
background: deeppink;
font-size: 0.9rem;
padding: 0.5rem;
margin: 0;
}
<div class="reference">Elemento de referencia</div>
<div class="element">Elemento a posicionar</div>
Como ves, por defecto, los elementos 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, en este caso no se usa la función var()
.
Bien, hemos definido el punto de anclaje, pero aún no estamos haciendo nada.
La propiedad position-anchor
Por otro lado, una vez tenemos un punto de anclaje definido, podemos utilizar la propiedad position-anchor
para posicionar elementos respecto al mencionado punto de anclaje, indicándole su nombre.
En el ejemplo anterior definimos un punto de anclaje --first-box
, así que vamos a añadir un position-anchor
para referenciarlo. Atento a que necesitaremos posicionar el elemento y usar la función anchor()
:
.reference {
max-width: 150px;
margin: auto;
margin-top: 4rem;
padding: 0.5rem;
background: #444;
anchor-name: --first-box; /* Creamos referencia */
}
.element {
max-width: 75px;
background: deeppink;
font-size: 0.9rem;
padding: 0.5rem;
margin: 0;
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️⃣ Hemos creado un punto de anclaje con
anchor-name
:--first-box
. - 2️⃣ Luego, hemos posicionado
.element
conabsolute
. Debe estar posicionado. - 3️⃣ Por último, hemos indicado a que elemento lo anclamos 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. Esta parte la explicaremos un poco más adelante.
La propiedad anchor-scope
La propiedad anchor-scope
nos permite limitar el ámbito de anclaje, algo que es muy útil si tenemos muchos elementos repetidos y queremos acotar su aplicación.
Los valores que tiene esta propiedad son los siguientes:
Propiedad | Descripción |
---|---|
none | No limita nada. Valor por defecto. |
all | Todos los anchor-name sólo son visibles dentro de sus hijos. |
dashed-ident | Similar a all , pero sólo para nombres de anclajes con este nombre, prefijado por -- . |
Con esta propiedad podemos evitar que se solapen los elementos anclados y, por ejemplo, con el valor all
, limitas que sólo vean su propio elemento y descendientes y no los externos.
Funciones de posicionamiento
Además de lo que hemos visto hasta ahora, tenemos a nuestra disposición dos funciones CSS muy útiles que nos ayudarán a trabajar con anclajes:
- 1️⃣ La función
anchor()
: Posiciona el elemento respecto a su punto de anclaje. - 2️⃣ La función
anchor-size()
: Devuelve el tamaño del punto de anclaje indicado por parámetro.
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
otop
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 lo anterior, tenemos dos propiedades más que son muy interesantes:
- La propiedad
position-area
: Indica el área donde vamos a conectar el elemento. - La propiedad
position-visibility
: Indica la visibilidad del elemento.
La propiedad position-area
La propiedad position-area
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.
Los valores clave de dicha propiedad son los siguientes:
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;
position-area: top;
}
<label>
Propiedad <strong>position-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(`--position-area`, value);
});
Además, la propiedad position-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.
La propiedad position-visibility
La propiedad position-visibility
nos permite modificar el comportamiento del posicionado de elementos y decidir mostrarlo o no, dependiendo de si tiene espacio suficiente o si el anchor es correcto. Los valores de la propiedad position-visibility
son los siguientes:
Valor | Descripción |
---|---|
auto | El navegador decide. Generalmente actua como anchors-valid-and-fit . |
always | El elemento posicionado aparece siempre (aunque esté mal anclado, sin espacio, etc...). |
anchors-valid | El elemento sólo se renderiza si su anchor es válido (existe y está en el scope). |
anchors-valid-and-fit | El elemento sólo se renderiza si su anchor es válido y cabe sin recortarse. |
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;
position-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.