DEV Community

Cover image for Guía completa y práctica sobre posicionamiento CSS: z-index y stacking context
Lupita Code 🌄
Lupita Code 🌄

Posted on

Guía completa y práctica sobre posicionamiento CSS: z-index y stacking context

¡Hola gente bonita!👋

Este es el ultimo articulo de la guía completa de posicionamiento en CSS, en el cual voy a explicar la propiedad z-index. Esta propiedad nos permite definir la posición en el eje z de los elementos posicionados.

🧐 ¿Cómo funciona z-index?

Cuando los elementos se colocan fuera del flujo normal, pueden superponerse sobre otros elementos. La propiedad z-index especifica el orden de apilamiento (Stacking Context) en el eje z, es decir, cual elemento debe ser colocado enfrente o detrás de otros.

La propiedad z-index acepta un valor numérico que puede ser un número positivo o negativo, no se usa unidades tales como pixeles o porcentajes. Esta propiedad toma un valor numérico entre 0 y ±2147483647 en la mayoría de los navegadores comunes.

El valor por defecto de z-index es auto. El navegador irá ordenando los elementos en el orden que aparezcan en el documento HTML, el primer elemento quedara debajo y los siguientes elementos se irán apilando encima, pero con la propiedad z-index podemos modificar este orden, esto lo puedes comprobar con los siguientes ejemplos:

Ejemplo 1️⃣

En el siguiente ejemplo tenemos 3 cajas que están dentro de un contenedor, no estarán posicionadas y tampoco tendrán un z-index declarado, solo tendrán un margin-top.

<div class="demo">
  <div class="box-1">1</div>
  <div class="box-2">2</div>
  <div class="box-3">3</div>
</div>
Enter fullscreen mode Exit fullscreen mode
.demo {
    width: 300px;
    height: 300px;
    padding: 2rem;
    border: 2px dashed black;
}

[class^="box-"] {
    width: 100px;
    height: 100px;
    padding: 30px 10px;
    font-size: 2rem;
    font-weight: bold;
    text-align: center;
}

.demo > * + * {
    margin-top: -50px; ⬅️
    opacity: 0.8;
    box-shadow: 0 -1px 10px rgba(0, 0, 0, 60%);
}

.box-1 {
    background-color: pink;
    border: 2px solid hotpink;
}

.box-2 {
    background-color: tomato;
    border: 2px solid orangered;
}

.box-3 {
    background-color: wheat;
    border: 2px solid gold;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text
Recordemos que a ninguna caja se le ha especificado la propiedad z-index y tampoco están posicionadas, podemos ver en la imagen que las cajas se han apilado, entonces ¿Cómo decide el navegador cual colocar encima del otro? la respuesta es que si no hay un z-index el navegador usa el orden en el que aparecen en el documento HTML. El que aparece después siempre va "encima" de los otros elementos.

Si revisamos el código HTML, primero tenemos la caja con el numero uno por eso esta detrás de la caja dos y al final esta la caja tres por eso esta encima de todas las cajas.

En resumen la caja amarilla se coloco encima de la caja roja, porque dicha caja se coloco después en el documento HTML, aunque la propiedad z-index puede cambiar este orden.

Ejemplo 2️⃣

Antes de explicar como funciona la propiedad z-index, vamos a ver otro ejemplo solo con dos cajas, si a la primera caja la posicionamos con el valor de relative y la movemos con la propiedad top: 50px, esta caja se coloca encima de la caja dos y esto es porque en el documento HTML la caja uno esta primero.

.demo > * + * {
    /* eliminamos el margin-top */
    box-shadow: 0 -1px 10px rgba(0, 0, 0, 60%);
}

.box-1 {
    position: relative; ⬅️
    top: 50px; ⬅️
    background-color: pink;
    border: 2px solid hotpink;
}

.box-2 {
    background-color: tomato;
    border: 2px solid orangered;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text
Como puedes ver la segunda caja no esta posicionada por lo tanto la caja uno se coloca encima. Pero, ¿Qué pasaría si a la caja dos también le agregamos el posicionamiento relative?, vamos a explicarlo con el siguiente ejemplo:

.box-1 {
    position: relative; ⬅️
    top: 50px; ⬅️
    background-color: pink;
    border: 2px solid hotpink;
}

.box-2 {
    position: relative; ⬅️
    background-color: tomato;
    border: 2px solid orangered;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

A la segunda caja solo se le agregó el valor relative y se coloco encima de la primera caja, ¿Por qué sucede esto? la respuesta es que, si ambos elementos están posicionados sin tener un z-index declarado lo que prevalece es el orden en el que aparecen en el documento HTML.

Aunque no especifiques un z-index los elementos van aparecer según su orden en el flujo normal.

Ejemplo 3️⃣

Vamos a continuar con los ejemplos anteriores ahora vamos a tener tres cajas, que estarán posicionadas, para no estar colocando a cada elemento la propiedad position vamos hacer uso del selector de atributo.

⚠️ Recuerda que si estableces un valor especifico para z-index en un elemento y si no esta funcionando es porque necesitas establecer un tipo de posicionamiento diferente de static. Este es el error mas común donde los desarrolladores luchan con z-index.

🔎 Sin embargo, si estas usando flexbox o grid, si puedes modificar el z-index de los elementos flex o grid sin añadir position: relative.

[class^="box-"] {
    position: relative; ⬅️
}
.box-1 {
    top: 50px;  ⬅️
    left: 50px; ⬅️
    background-color: pink;
    border: 2px solid hotpink;
}

.box-2 {
    top: 10px;   ⬅️
    left: 100px; ⬅️
    background-color: tomato;
    border: 2px solid orangered;
}

.box-3 {
    left: 150px; ⬅️
    top: -50px;  ⬅️
    background-color: wheat;
    border: 2px solid gold;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

La propiedad z-index puede cambiar este orden, si asignamos solamente a la caja dos un z-index con valor 1 la caja dos se coloca encima de las demás.

.box-2 {
    top: 10px;
    left: 100px;
    z-index: 1; ⬅️
    background-color: tomato;
    border: 2px solid orangered;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

Pero, ¿Qué pasa si a la caja tres también le coloco un z-index con valor 1? la respuesta es que vamos a volver al mismo estado que teníamos anteriormente:

.box-2 {
    z-index: 1; ⬅️
}

.box-3 {
    z-index: 1; ⬅️
}

Enter fullscreen mode Exit fullscreen mode

Alt Text

Recordemos que la primera caja no tiene declarado un valor para z-index, pero en el siguiente ejemplo a cada una de las cajas le vamos a dar un valor diferente.

Ejemplo 4️⃣

En el siguiente ejemplo las cajas uno y tres estarán encima de la caja numero dos, las tres cajas tienen valores consecutivos en z-index, es decir la primera caja tiene un valor de 3, la segunda caja tiene un valor de 1 y la tercer caja tiene un valor de 2.

.box-1 {
    z-index: 3; ⬅️
}

.box-2 {
    z-index: 1; ⬅️
}

.box-3 {
    z-index: 2; ⬅️
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

🧠 Recuerda que si el elemento tiene un valor mayor en z-index se colocara encima de los otros elementos que tengan un valor menor.

➖ z-index negativo

Para colocar un elemento detrás de otro, tienes que añadir un valor negativo en z-index, aunque hay algunos casos particulares como los que se muestran en los siguientes ejemplos, antes de eso vamos a responder una pregunta interesante.

🤔 ¿Por que no es recomendado usar valores consecutivos en la propiedad z-Index?

Siguiendo con el ejemplo anterior de la imagen, ahora te propongo un reto. ¿Qué pasaría si ahora quiero que la caja dos este encima de la caja tres, pero que este debajo de la caja uno?

Tu solución podría ser colocar un valor superior a la caja dos, lo que implica eliminar el valor anterior que tenias en dicha caja: z-index : 1 y ahora reemplazarlo por un valor mayor, digamos que colocas: z-index: 3 ahora la caja dos se coloca encima de la caja tres y es correcto pero recuerda que también hay que colocar la caja dos debajo de la caja uno, pero ese valor que colocaste en la caja dos ya lo tiene la caja uno, entonces tienes que estar cambiando los valores.
Entonces después de estar comprobando, La posible solución a la que quizás llegaste fue esta:

.box-1 {  
    z-index: 3;
}

.box-2 {   
    z-index: 2;  
}

.box-3 {   
    z-index: 1;
}
Enter fullscreen mode Exit fullscreen mode

Si bien es correcto no es la manera mas optima, y esto sucede porque hemos colocado valores consecutivos: 1,2,3 en las cajas, y al momento de querer cambiar el orden de las cajas vas a tener que cambiar los valores y si quieres agregar una caja extra que también tenga un z-index declarado se puede volver complicado.

Cuando tengas varios elementos la mejor practica es tener un rango numérico amplio, puede ser: 10, 20, 30 para darle espacio a nuevos elementos cuando quieras agregar un z-index a cada uno de ellos.

En este ejemplo agregue un rango de valores a cada una de las cajas, si hay otro elemento extra que quiera incluir, por ejemplo una cuarta caja y si agrego un z-index puedo colocar el valor de 11 ya que ese valor no estará ocupado por ningún otro elemento, así que es una buena practica hacerlo de esta manera.

.box-1 {  
    z-index: 20;
}

.box-2 {   
    z-index: 15;  
}

.box-3 {   
    z-index: 10;
}
Enter fullscreen mode Exit fullscreen mode

El resultado es el siguiente:

Alt Text

👨‍👦 Relación padre-hijo

En el siguiente ejemplo vamos a tener dos elementos, el primero es un elemento contenedor, este va a tener un elemento adentro, es decir, una relación padre-hijo.

Ejemplo 5️⃣

<div class="container">
  <div class="item"></div>
 </div>
Enter fullscreen mode Exit fullscreen mode
.container {
    position: relative;
    width: 200px;
    height: 200px;
    padding: 2rem;
    background-color: lightblue;
}

.item {
    position: relative;
    top: -70px;
    left: 100px;
    width: 100px;
    height: 100px;
    background-color: tomato;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

Ahora queremos que el contenedor padre (color lightblue) se coloque encima del contendor hijo (color tomato), parece fácil y quizás tu primera solución seria solo agregar un valor al z-index del contenedor y listo pero no es tan simple como parece ya que esto no funcionara. ¡Pongámoslo a prueba!

.container {
    position: relative;
    z-index: 20;
}
.item {
    position: relative;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

Como puedes observar no ha pasado nada, el contenedor no se coloco encima del elemento hijo, quizás tu segunda solución sea colocar en el elemento hijo un valor negativo tal vez un -30 y si puede que esto funcione. ¡Pongámoslo a prueba!

.container {
    position: relative;
    z-index: 20;
}
.item {
    position: relative;
    z-index: -30;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

Como puedes observar tampoco ha funcionado, no se ha comportado de la manera que quieres, ¡incluso si estableces z-index a 999999! o agregas la declaración !important, pero ¿Por que sucede? Esto se debe a que el contenedor padre sigue teniendo un z-index declarado, si no lo tuviera, si funcionaria. Vamos a comprobarlo:

.container {
    /* Eliminamos el z-index */
    position: relative;
}
.item {
    position: relative;
    z-index: -30;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

Entonces podemos decir que si el elemento padre tiene un z-index declarado, el elemento hijo no se podrá colocar encima de el, a menos que el contenedor padre no tenga la propiedad z-index y el elemento hijo lo tenga con valor negativo

:: Pseudoelementos

En nuestro siguiente ejemplo vamos a utilizar el pseudoelemento ::before. El comportamiento es similar a lo que sucede en el ejemplo anterior, también puedes usar ::after para hacer este ejercicio.

 <div class="box"></div>
Enter fullscreen mode Exit fullscreen mode
.box {
    position: relative;
    width: 200px;
    height: 200px;
    background-color: tomato;
}

.box::before {
    content: "";
    width: 150px;
    height: 150px;
    position: absolute;
    top: 130px;
    left: 130px;
    background-color: rebeccapurple;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

Es importante comprender que los pseudoelementos son como hijos del elemento del cual son generados.
Si queremos que el pseudoelemento ::before se coloque detrás de la caja box entonces la única manera es declarar un z-index en el pseudoelemento cuyo valor sea negativo, y que el elemento que los origina no tenga un z-index declarado. Es lo mismo que sucede en el ejemplo anterior cuando la relacion es padre-hijo.

Recuerda que los pseudoelementos ::before y ::after cuando tienen un posicionamiento absoluto, en automatico van aparecer encima del elemento al cual pertenecen o del cual se originan.

.box {
    position: relative;
    width: 200px;
    height: 200px;
    background-color: tomato;
}

.box::before {
   z-index: -100;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

📋 Conclusión

☑️ La propiedad z-index permite modificar el orden de las capas.
☑️ Aunque no especifiques un valor en z-index los elementos van aparecer según su orden en el flujo normal.
☑️ Para poder utilizar la propiedad z-index primero debes posicionar los elementos.
☑️ La propiedad z-index admite valores numéricos positivos/negativos en un rango de 0 y ±2147483647.
☑️ Es recomendable no usar valores consecutivos como: 1,2,3,4,5..., se considera un buena practica separar los valores de la propiedad z-index por rangos numéricos amplios.
☑️ En algunos casos puede que no sea necesario el uso de z-index.
☑️ Si hay un elemento padre con un z-index declarado, el elemento hijo no se podrá colocar encima de el, a menos que el contenedor padre no tenga la propiedad z-index y el elemento hijo lo tenga con valor negativo, este problema también sucede con los pseudoelementos.
☑️ Si estas usando flexbox o Grid, si puedes modificar el z-index de los elementos flex o grid sin añadir position: relative.

🔎Recursos:

Gracias por leer🦸🏻‍♀️
Mis redes sociales donde comparto notas de código:

▶️Youtube
📷Instagram
🐦Twitter
🔵Facebook
🔲Codepen
✍️Medium
🎵Tik Tok

Discussion (4)

Collapse
renatoayau profile image
Renato Ayau

Excelente explicacion.

Collapse
lupitacode profile image
Lupita Code 🌄 Author

Muchas gracias! :)

Collapse
angeluchh profile image
Angel Rodríguez

Increible Post!!! siempre me costo mucho trabajo entender los pseudoelementos!! gracias por los recursos que nos compartes..

Collapse
lupitacode profile image
Lupita Code 🌄 Author

Es un placer ayudar Ángel :)