Position absolute

Position absolute

Aprenderemos cómo funciona al valor `absolute` cuando estamos posicionando un elemento con CSS.

El valor absolute para el atributo CSS position es una de las cosas más útiles que tenemos a nuestra disposición para poder posicionar los elementos que forman parte de nuestras páginas pero tenemos que ser conscientes de que siempre lo vamos a poder utilizar cuando este posicionamiento esté relacionado con el de otros elementos que forman parte de nuestra página lo cual suele confundirnos bastante si no es algo que tengamos controlado.

Position: absolute

Para poder entender cómo funciona absolute lo que vamos a hacer es basarnos en un ejemplo donde necesitemos este posicionamiento. Para ello vamos a suponer que estamos construyendo un juego y que dentro del marcado de nuestra página tenemos un <div> en el que recogeremos el contenido de dicho juego simulando a la pantalla de una consola portátil:

<div class="game-board"></div>

Ahora bien, nuestra idea es que dentro de este <div> vamos a querer situar otro <div> en el que recogeremos una serie de imágenes que simularán el mando del juego (pad) entendiendo como tal los botones que nos van a permitir avanzar hacia arriba, abajo, izquierda y derecha.

<div class="game-board">
  <div class="d-pad">adf</div>
</div>

Nota: lo realmente importante de la explicación que estamos haciendo no es tanto el contenido de este d-pad (las flechas) sino el posicionamiento del mismo por lo que inicialmente vamos a hacer que su contenido sea una cadena de caracteres aleatoria adf en nuestro ejemplo.

Si nos vamos a nuestro navegador para ver qué es lo que hemos conseguido hasta ahora el resultado será realmente simple puesto que no hemos aplicado ningún estilo:

Vamos por lo tanto con los estilos CSS y en primer lugar nos ocuparemos del game-board donde lo que vamos a hacer es darle un anchura y altura y además le estableceremos un borde para poderlo ver representado en nuestro navegador:

.game-board {
  border: 5px solid black;
  height: 400px;
  width: 400px;
}

Si ahora guardamos nuestro trabajo y volvemos a recargar el navegador nos vamos a encontrar con algo parecido a lo que podemos ver en la siguiente imagen:

Ahora nos vamos a plantear el centrar el contenido de la página o, dicho de otra manera, que el game-board se muestre en el centro de la misma y para ello, suponiendo que nuestra página únicamente tiene este elemento lo que hacemos es crear las siguientes reglas CSS donde centraremos el contenido a partir de aplicar estilos sobre la etiqueta <body>:

body {
  display: grid;
  min-height: 100vh;
  place-items: center;
}

Nota: evidentemente existen muchas maneras de centrar un <div> en CSS aunque en este caso he preferido utilizar la que se puede ver en la declaración anterior donde declaramos un grid que ocupa todo el espacio vertical y luego lo que hacemos es posicionar los elementos dentro de este grid en el centro.

Tras este código el aspecto de nuestro tablero de juego ahora será el que vemos a continuación:

Vamos ahora con los estilos que queremos aplicar sobre d-pad donde lo que queremos hacer es aplicar una anchura, una altura, le aplicaremos un color de fondo para poderlos resaltar en la página y por último un color al borde que lo delimita:

.d-pad {
  background: lightgreen;
  border: 5px solid darkgreen;
  height: 50px;
  width: 50px;
}

Esto nos deja algo parecido a lo que se puede ver en la siguiente imagen:

Centrando el d-pad

Una vez tenemos nuestros estilos básicos creados lo siguiente que vamos a tener que hacer es posicionar nuestro d-pad para que esté situado en la esquina inferior derecha de nuestra página y para ello comenzaremos estableciendo que su posición es absolute y le establecemos un valor en píxeles de cuál es la distancia que queremos que tenga con respecto a la parte inferior de su contenedor. Por lo tanto escribimos:

.d-pad {
  bottom: 150px;
  position: absolute;

  background: lightgreen;
  border: 5px solid darkgreen;
  height: 50px;
  width: 50px;
}

Con esto hemos logrado situar el d-pad en el sitio que se puede ver en la siguiente imagen:

y no solamente eso sino que si además le añadimos una distancia en píxeles con respecto a la parte derecha de su contenedor como sigue:

.d-pad {
  bottom: 150px;
  position: absolute;
  right: 125px;

  background: lightgreen;
  border: 5px solid darkgreen;
  height: 50px;
  width: 50px;
}

El resultado lo podemos ver en la siguiente imagen donde de alguna manera lo que tratamos de lograr es que el d-pad esté situado en la parte inferior derecha de la página simulando de esta manera que es ahí el lugar en el que estarían los controles que nos permitirían interactuar con nuestro video juego:

Ahora la pregunta que surge es ¿con quién está posicionado absolute nuestro d-pad? Pues para verlo simplemente tenemos que cambiar el tamaño de la página y ver qué es lo que está pasando:

¿Por qué no está funcionando cómo nos gustaría? Pues aquí tenemos que entender que en primer lugar estamos usando una serie de magic numbers para determinar la distancia del d-pad con respecto a la parte inferior y con respecto a la parte derecha del elemento que lo contiene y que tiene un posicionamiento relativo. La pregunta ahora es ¿qué elemento tiene el posicionamiento relativo? Pues como no lo hemos especificado de forma explícita en el elemento game-board que lo contiene será con respecto al siguiente elemento en la jerarquía de nuestro DOM que no es otro que el elemento <body>razón por la que nuestro d-pad siempre se muestra en la misma posición cuando estamos redimensionando la página.

Y no solamente el posicionamiento se sigue respetando en el momento en el que redimensionamos la página puesto que además si hacemos zoom in o zoom out se seguirá respetando que siempre se tendrá la misma distancia con respecto a la parte inferior y derecha que hemos declarado:

Position relative

Para poder lograr que nuestro d-pad se posicione con respecto al game-board simplemente lo que vamos a tener que hacer es declarar que game-board define una posición relative para todos los elementos que contenga de tal manera que estos sabrán posicionarse con respecto al game-board en el caso de que definamos un posicionamiento absolute:

.game-board {
  position: relative;

  border: 5px solid black;
  height: 400px;
  width: 400px;
}

Y simplemente con este cambio podemos ver cómo ahora el d-pad se posiciona con respecto al game-board respetando la distancia a la parte inferior y a la parte derecha que se ha declarado:

Es más si ahora hacemos zoom in o zoom out vamos a ver que el posicionamiento se conservará tal y como esperábamos:

Esto ocurre porque en el momento en el que declaramos d-pad con la posición absolute y game-board con la posición relative es game-board quien pasa a ser el viewport a partir del cual se situarán los elementos que están recogidos dentro del mismo y que tengan el posicionamiento absolute.

Custom Properties para simplificar

El problema que se nos presenta a la hora de hacer zoom in y zoom out es que nuestro d-pad se posiciona correctamente respectando la distancia que hemos definido pero esta distancia está marcada con valores absolutos (valores fijos) lo que supone no siempre nuestro d-pad aparezca en el lugar que nos gustaría en la página y nos gustaría que esto no fuese así sino que el posicionamiento fuese consistente sin importar el nivel de zoom que tengamos.

Así pues vamos a comenzar posicionando todavía más próximo al vértice inferior derecho nuestro d-pad como sigue:

.d-pad {
  bottom: 20px;
  position: absolute;
  right: 200px;

  background: lightgreen;
  border: 5px solid darkgreen;
  height: 50px;
  width: 50px;
}

Esto nos deja nuestro posicionamiento tal cual se puede ver en la siguiente imagen:

El truco para lugar nuestro objetivo va a ser definir una custom property de CSS a la que vamos a denominar --pixel-size a la que le asignaremos un valor que nos ayude a posicionar nuestro d-pad. Es más, como se trata de una custom property la podríamos definir a nivel del :root dentro del código CSS para que estuviese disponible para toda la página pero en este caso vamos optar por establecerla en game-board puesto que de esta manera estará disponible para el mismo y todos sus elementos hijos:

.game-board {
  --pixel-size: 5px;

  position: relative;

  border: 5px solid black;
  height: 400px;
  width: 400px;
}

Con este cambio no se producirá ninguna modificación en lo que se muestra en la página pero lo que sí que nos va a permitir es que vamos a poder utilizarlo a la hora de establacer los valores del posicionamiento con respecto al borde inferior y la esquina derecha del d-pad. Así pues escribiremos:

.d-pad {
  bottom: var(--pixel-size);
  position: absolute;
  right: var(--pixel-size);

  background: lightgreen;
  border: 5px solid darkgreen;
  height: 50px;
  width: 50px;
}

lo que hace que una vez guardemos nuestros cambios en la página d-pad se posicionará con una distancia de 5 píxeles con respecto a la parte inferior y a parte derecha del game-board tal y como podemos esperar puesto que este es el valor que tiene asignado --pixel-size:

y no solamente eso sino que asi además hacemos zoom in o zoom out esta distancia se mantendrá en todo momento:

La idea detrás de la declaración de este --pixel-size es definir lo que nosotros queremos que sea nuestro tamaño de píxel entendiendo como tal una unidad de medida que nos va a permitir calcular distancias y que todas las operaciones de posicionamiento en el contenedor en el que la definimos la tengan en cuenta. Así, si lo que queremos es que nuestro d-pad se sitúe a un total de 20 píxeles de distancia de la parte inferior y de la parte derecha del game-board lo que tendremos que hacer será apoyarnos en el uso de la función calc() de CSS sabiendo que el multiplicador que tendremos que aplicar en este caso será el número 4:

.d-pad {
  bottom: calc(var(--pixel-size) * 4);
  position: absolute;
  right: calc(var(--pixel-size) * 4);

  background: lightgreen;
  border: 5px solid darkgreen;
  height: 50px;
  width: 50px;
}

y simplemente con este cambio habremos logrado situar nuestro d-pad tanto a 20 píxeles del borde inferior como a 20 píxeles del border derecho de nuestro game-board:

Pero no deberíamos quedarnos ahí sino que además deberíamos tratar de definir el tamaño de nuestro game-board haciendo uso a su vez de --pixel-size. Así si queremos redefinir el tamaño del mismo para que pase a ser de 200x200 píxeles escribiríamos algo como:

.game-board {
  --pixel-size: 5px;
  position: relative;

  border: 5px solid black;
  height: calc(var(--pixel-size) * 20);
  width: calc(var(--pixel-size) * 20);
}

lo que nos deja lo siguiente:

Con esto hemos logrado que los elementos que forman parte del juego (el game-board y el d-pad) pasen a que puedan ser modificado su tamaño y su posicionamiento de una forma muy sencilla gracias al uso de la --pizel-size. Esto lo podemos ver si cambiamos su valor:

.game-board {
  --pixel-size: 10px;
  position: relative;

  border: 5px solid black;
  height: calc(var(--pixel-size) * 20);
  width: calc(var(--pixel-size) * 20);
}

donde al recargar la página el game-board se redimensiona para amoldarse al nuevo tamaño y el d-pad se situará a una distancia consistente con respecto a la distancia que hay cuando el tamaño del píxel era de 5 en lugar de 10.

Nota: evidentemente podríamos haber hecho que d-pad su tamaño fuese también relativo a --pixel-sixe pero hemos preferido dejar las cosas lo más sencillas posible.

Posicionamiento negativo

¿Qué ocurre en el caso que alguno de los elementos que vamos a posicionar tengan que tener un valor negativo? Por ejemplo, ¿cómo podemos hacer que el d-pad se sitúe una cantida de píxeles por debajo del extremo inferior de nuestro game-board?

Pues la respuesta es sencilla puesto que lo que tenemos que lograr es que el valor que se le asigne al posicionamiento asociado (en el ejemplo que estamos comentando bottom) sea un valor negativo y cómo estamos ante una operación matemática en calc() si multiplicamos por un valor negativo tendremos un número negativo tal y como querríamos:

.d-pad {
  bottom: calc(var(--pixel-size) * -4);
  position: absolute;
  right: calc(var(--pixel-size) * 4);

  background: lightgreen;
  border: 5px solid darkgreen;
  height: 50px;
  width: 50px;
}

Si guardamos el trabajo y vemos cómo se han cargado las cosas en el navegador nos encontraremos algo como lo siguiente donde efectivamente podemos ver que d-pad se sitúa 20 píxeles por debajo del extremos inferior del game-board tal y como esperábamos:

Código completo

A continuación se muestra el código CSS completo que hemos ido desarrollando en el ejemplo que hemos estudiado:

body {
  display: grid;
  min-height: 100vh;
  place-items: center;
}

.game-board {
  --pixel-size: 5px;
  position: relative;

  border: 5px solid black;
  height: calc(var(--pixel-size) * 20);
  width: calc(var(--pixel-size) * 20);
}

.d-pad {
  bottom: calc(var(--pixel-size) * 4);
  position: absolute;
  right: calc(var(--pixel-size) * 4);

  background: lightgreen;
  border: 5px solid darkgreen;
  height: 50px;
  width: 50px;
}