Guía completa y práctica sobre posicionamiento CSS: z-index y stacking context
Tags: css, html, spanish, latam
Published: 2021-05-26 21:08:08

¡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>
```
```
.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;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xmbkul5r52ulcnfdk8st.png)
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;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qah6a0ach98gkiirzzvp.png)
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;
}
``` 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iambacbhztrjbe1gv6kr.png)

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;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9rk1yqug8dp0yz0x75fc.png)

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;
}
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/upch8m4rzw3e9fx63q8s.png)

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; ⬅️
}

```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9rk1yqug8dp0yz0x75fc.png)

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; ⬅️
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eipm14zv9g393eb6owbv.png)

🧠 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;
}
```
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;
}
```
El resultado es el siguiente:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5psazltlroo9sqmwk5kv.png)

##👨‍👦 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>
```
```
.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;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nix1q2qsul4w1qemntj0.png)

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;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nix1q2qsul4w1qemntj0.png)

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;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nix1q2qsul4w1qemntj0.png)

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;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dg8udgawsakrhzdad9mg.png)

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>
```

```
.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;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zy3eso4kigm4qjp6vq57.png)

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;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lfpeypxc7fmqwa2o5wlg.png)

##📋 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:

* [z-index | web dev](https://web.dev/learn/css/z-index/)
* [Understanding z-index in CSS | Ahmad Shadeed](https://ishadeed.com/article/understanding-z-index/)
* [What the heck, z-index?? | Josh Comeau](https://www.joshwcomeau.com/css/stacking-contexts/)
* [4 reasons your z-index isn’t working (and how to fix it)](https://coder-coder.com/z-index-isnt-working/)
* [Managing CSS Z-Index In Large Projects](https://www.smashingmagazine.com/2021/02/css-z-index-large-projects/)
* [Learn Z-Index Using a Visualization Tool](https://thirumanikandan.com/posts/learn-z-index-using-a-visualization-tool)
* [CSS Painting Order](https://abandonedwig.info/blog/2020/07/03/css-painting-order.html)


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

[▶️Youtube](https://www.youtube.com/lupitacode)
[📷Instagram](https://instagram.com/lupitacode)
[🐦Twitter](https://twitter.com/lupitacode)
[🔵Facebook](https://facebook.com/lupitacode)
[🔲Codepen](https://codepen.io/lupitacode/)
[✍️Medium](https://lupitacode.medium.com/)
[🎵Tik Tok](https://www.tiktok.com/@lupitacode)