Qué deberías saber sobre la propiedad z-index de CSS, una declaración que esconde muchos secretos y detalles que pueden producir más de un quebradero de cabeza al definir estilos en la página.
Analizamos la propiedad CSS z-index para intentar descifrar su correcto uso más allá del habitual conocimiento que tenemos de ella, normalmente consistente en saber que las capas con mayor valor de z-index se colocan delante de las de valor menor.
El problema con z-index es que muy poca gente comprende cómo funciona realmente. No es complicado, pero si nunca te has tomado la molestia de leer su especificación, hay ciertamente algunos aspectos cruciales que has pasado por alto.
¿No me crees? Bien, veamos si puedes solventar este problema:
El problema
En el siguiente HTML tienes tres elementos <div>
, y cada <div>
contiene un único elemento <span>
. Cada <span>
tiene un color de fondo — rojo, verde y azul respectivamente. Cada <span>
está también posicionado absolutamente cerca de la posición superior izquierda del documento, escasamente solapando a los otros elementos <span>
así que puedes ver cuáles están apilados en frente de cada cual. El primer <span>
tiene un valor z-index de 1, mientras que los otros dos no tienen ningún valor z-index fijado.
Aquí tenemos el HTML y CSS básicos para entenderlo. También he incluido una demo visual (vía Codepen) con el código que se muestra a continuación:
<div>
<span class="rojo">Rojo</span>
</div>
<div>
<span class="verde">Verde</span>
</div>
<div>
<span class="azul">Azul</span>
</div>
.rojo, .verde, .azul {
position: absolute;
}
.rojo {
background: red;
z-index: 1;
}
.verde {
background: green;
}
.azul {
background: blue;
}
Puede verse el ejemplo completo aquí.
Aquí está el desafío: intenta ver si puedes hacer que el <span>
rojo se apile detrás del azul y del verde sin romper ninguna de las siguiente reglas:
- No alteres el HTML de ninguna manera.
- No añadas o cambies la propiedad z-index de ningún elemento.
- No añadas o cambies la propiedad de posicionamiento de ningún elemento.
- Para que puedas hacerte una idea clara, cliquea en "edit" en el enlace de Codepen que hay arriba y juega un momento con el código. Si tienes éxito, debería quedarte algo como lo que sigue. Prueba aquí.
La solución
La solución es añadir un valor de opacidad menor que 1 en el primer <div>
(el padre del <span>
rojo). Aquí está el CSS que se añade al Codepen:
div:first-child {
opacity: .99;
}
Si te estás rascando la cabeza ahora mismo en estado de shock y te muestras estupefacto por el hecho de que esa opacidad haya causado efecto en cómo los elementos se apilan los unos respecto a los otros, bienvenido al club. Me pasó lo mismo cuando tropecé la primera vez con el mismo problema.
Tranquilo, el resto del artículo dejará las cosas un poco más claras.
Ordenar el apilamiento
Z-index parece sencillo: elementos con un z-index mayor son apilados delante de los elementos con un menor z-index, ¿no? Bien, de hecho, no. Esto es parte del problema del z-index. Parece sencillo, así que los desarrolladores no dedican tiempo a leer sus reglas.
Cada elemento en un documento HTML puede estar delante o detrás de otro elemento en el documento. Esto se conoce como el orden de apilamiento. Las reglas que determinan este orden están bonita y claramente definidas en la especificación, pero como he constatado, no son completamente entendidas por la mayoría de desarrolladores.
Cuando el z-index y las propiedades de posición no están declaradas, las reglas son muy simples: básicamente, el orden de apilamiento es el mismo que el orden de aparición en el HTML. (DE ACUERDO, es de hecho un poco más complicado que eso, pero si no estás usando márgenes negativos para solapar elementos en la misma línea de posición, probablemente no te encontrarás con elementos problemáticos).
Cuando introduces la propiedad de posición en la mezcla, cualesquiera elementos posicionados (y sus hijos) se muestran delante de elementos no posicionados (decimos que un elemento está "posicionado" cuando tiene un valor de posición distinto de "static", como "relative", "absolute", etc.)
Finalmente, cuando el z-index se involucra también, las cosas se complican un poco. Al principio es natural asumir que los elementos con valores z-index mayores están delante de los elementos con valores z-index menores, y que cualquier elemento con z-index está en frente de los elementos que no tienen z-index, pero no es tan simple. Lo primero de todo, z-index solo funciona con elementos posicionados. Si intentas asignarle un z-index a un elemento sin posición especificada, no hará nada. En segundo lugar, los valores z-index pueden crear contextos de apilamiento, y ahora de pronto lo que parecía sencillo es bastante más complicado.
Contextos de apilamiento
Grupos de elementos con un padre común que se mueven hacia adelante o hacia atrás juntos en el orden de apilamiento, se integran en lo que es conocido como contexto de apilamiento. Una completa comprensión de los contextos de apilamiento es la llave para realmente captar cómo funciona el z-index y el orden de apilamiento.
Cada contexto de apilamiento tiene un elemento HTML como su elemento raíz. Cuando un nuevo contexto de apilamiento se forma en un elemento, ése contexto confina todos sus elementos hijos en un lugar particular del orden. Eso significa que si un elemento es contenido en un contexto de apilamiento en lo más bajo del orden, no hay manera de que aparezca delante de otro elemento en un contexto de apilamiento que está en un nivel superior en el orden, ¡incluso con un z-index de mil millones!
Los nuevos contextos de apilamiento pueden ser formados en un elemento de tres maneras:
- Cuando un elemento es el elemento raíz de un documento (el elemento
<html>
). - Cuando un elemento tiene un valor de posición que no sea "static" y valor de z-index distinto a "auto".
- Cuando un elemento tiene un valor de opacidad menor que uno.
La primera y la segunda manera de formar contextos de apilamiento tienen mucho sentido y son generalmente bien comprendidos por los desarrolladores web (incluso si no conocen el propio concepto de contexto de apilamiento).
La tercera manera (opacidad) es apenas mencionada fuera de los documentos de especificación de la W3C.
Determinando una posición de elemento en el orden de apilamiento
Actualmente, determinar el orden de apilamiento global para todos los elementos de una página (incluyendo bordes, fondos, capas de texto, etc.) es extremadamente complicado y se aleja del propósito de este artículo (de nuevo, hago referencia a la especificación). Pero para nuestro propósito, una comprensión básica del orden puede ayudar a desarrollar un CSS predecible. Así que vamos a dividir el orden en individuales contextos de apilamiento:
Orden de apilamiento dentro del mismo contexto de apilamiento
Aquí están las reglas básicas de orden de apilamiento dentro de un contexto simple (desde el fondo hacia delante):
- El contexto de apilamiento del elemento raíz.
- Elementos posicionados (y sus hijos) con valores z-index negativos (los valores más altos son apilados delante de valores menores; elementos con el mismo valor son apilados de acuerdo a su aparición en el HTML).
- Elementos no posicionados (ordenados por aparición en el HTML).
- Elementos posicionados (y sus hijos) con un valor z-index de auto (ordenados por aparición en el HTML).
- Elementos posicionados (y sus hijos) con valores z-index positivos (los valores mayores son apilados delante de valores menores; elementos con el mismo valor son apilados de acuerdo a su aparición en el HTML.
Orden de apilamiento global
Con una firme comprensión de cómo funcionan los contextos de apilamiento, y de cómo funciona el orden de apilamiento dentro de un contexto de apilamiento, imaginar dónde un elemento particular podrá aparecer en el orden de apilamiento global se convierte en una tarea más sencilla.
La clave es evitar la confusión generada cuando se forman nuevos contextos de apilamiento. Si pones un z-index con un valor de mil millones en un elemento y no se mueve hacia delante en el orden de apilamiento, echa un vistazo a su ancestro y mira si alguno de sus padres está formando contextos de apilamiento. Si lo hacen, tu z-index es inútil y no hace nada bueno.
En conclusión
Volvamos al problema original, donde recreé la estructura HTML añadiendo comentarios dentro de cada etiqueta indicado su lugar en el orden de apilamiento.
<div><!-- 1 -->
<span class="rojo"><!-- 6 --></span>
</div>
<div><!-- 2 -->
<span class="verde"><!-- 4 --><span>
</div>
<div><!-- 3 -->
<span class="azul"><!-- 5 --></span>
</div>
Cuando añadimos la regla de opacidad al primer <div>
, el orden de apilamiento cambia así:
<div><!-- 1 -->
<span class="rojo"><!-- 1.1 --></span>
</div>
<div><!-- 2 -->
<span class="verde"><!-- 4 --><span>
</div>
<div><!-- 3 -->
<span class="azul"><!-- 5 --></span>
</div>
"span.rojo" solía ser 6, pero cambió a 1.1. Se muestra que un nuevo contexto de apilamiento ha sido creado, y "span.rojo" es ahora el primer elemento dentro de ese nuevo contexto.
Espero que ahora esté un poco más claro por qué la caja roja se movió detrás de las otras cajas. El ejemplo original contenía solo dos contextos de apilamiento, el raíz y el formado por "span.rojo" Cuando hemos añadido opacidad al elemento padre de "span.rojo", hemos formado un tercer contexto de apilamiento, y, como resultado, el valor z-index de "span.rojo" solo se aplicaba dentro de ese nuevo contexto. Como el primer <div>
(el único al que le aplicamos opacidad) y sus elementos hermanos no tienen asignados ni posición ni valor de z-index, su orden de apilamiento es determinado por su orden de aparición en el HTML, lo cual significa que el primer <div>
, y todos los elementos contenidos dentro de su contexto de apilamiento son renderizados detrás del segundo y el tercer <div>
.
Recursos adicionales
Tenemos una FAQ muy aclaradora sobre problemas que te puede dar el z-index: ¿Por qué z-index no funciona?
El artículo original que se ha traducido en este espacio tenía además otras referencias interesantes, ya en inglés:
- Elaborate description of Stacking Contexts
- The stacking context
- The Z-Index CSS Property: A Comprehensive Look
Fuente: Philip Walton
OldMith
Desarrollador Web. jQuery. Responsive Design. Wordpress. Friki por naturaleza.