z-index y contextos de apilamiento CSS, desmontados en 3D
Guía de z-index y contextos de apilamiento CSS
¿z-index no funciona? Contextos de apilamiento, vista 3D | We.Inc
Por qué se ignora z-index, todas las propiedades que crean un contexto de apilamiento, una vista 3D despiezada de las capas, cabeceras sticky y menús desplegables, una escala de z-index y una lista de comprobación para depurar.
z-index ordena los elementos que se solapan, pero solo dentro del mismo contexto de apilamiento. Un hijo con z-index: 9999 no puede quedar por encima de un elemento de fuera de su padre si ese padre forma un contexto con un z-index más bajo. Los contextos los crean position junto con z-index, opacity por debajo de 1, transform, filter, isolation: isolate y varias propiedades más.
Por qué parece que se ignora z-index
Síntoma
Causa probable
z-index no tiene efecto
El elemento es position: static y no es hijo de un flex o un grid
Un z-index enorme sigue quedando detrás
Un ancestro forma un contexto de apilamiento en una capa más baja
El menú desplegable queda oculto bajo la sección siguiente
El padre tiene transform, opacity o filter
El menú se corta en el borde
overflow: hidden en un ancestro, no tiene nada que ver con z-index
La vista 3D de abajo separa una pequeña página en sus capas de apilamiento para que veas qué cajas quedan atrapadas dentro de qué contexto. Cambia los valores de z-index y activa o desactiva la propiedad que crea un contexto en el padre. Después vienen todos los desencadenantes según MDN, cabeceras sticky con menús desplegables, una escala de tokens y una rutina de depuración paso a paso.
Define los valores de z-index para la cabecera, la tarjeta y el menú desplegable que hay dentro de la tarjeta.
Activa en la tarjeta un desencadenante de contexto de apilamiento y mira cómo el menú desplegable queda atrapado.
Activa la vista 3D para ver las capas separadas y agrupadas por contexto.
Usa isolation: isolate o saca el menú desplegable del contexto para arreglarlo.
Antes de subir un número, localiza el contexto de apilamiento. Subir el z-index dentro de un contexto que lo atrapa nunca sirve de nada.
Guarda los valores de z-index en tokens con nombre y con huecos entre ellos, para que las capas nuevas encajen sin renumerar.
Usa isolation: isolate en los componentes para contener sus valores internos de z-index, de modo que no puedan pelearse con el resto de la página.
Para modales y popovers, el elemento nativo dialog y el atributo popover usan la capa superior, que queda por encima de cualquier z-index.
Preguntas frecuentes
¿Por qué no funciona z-index?
O el elemento no está posicionado (z-index necesita un position distinto de static, o un padre flex o grid), o está atrapado en un contexto de apilamiento. La posición del padre en su propio contexto decide el resultado, y los hijos no pueden escapar de ella, lleven el número que lleven.
¿Qué crea un contexto de apilamiento?
El elemento raíz, los elementos posicionados con un z-index, los elementos fixed y sticky, los hijos de flex y grid con un z-index, opacity por debajo de 1, las transformaciones, los filtros, clip-path, las máscaras, mix-blend-mode, perspective, isolation: isolate, algunos valores de contain y will-change, los contenedores de tamaño y los elementos de la capa superior.
¿Qué hace isolation: isolate?
Crea un nuevo contexto de apilamiento y nada más, sin ningún cambio visual. Ponlo en la raíz de un componente para que los hijos con z-index negativo se queden detrás del fondo del propio componente en vez de caer detrás de la página, y para que sus capas internas nunca se mezclen con las de fuera.
¿Cómo mantengo un menú desplegable por encima de la sección siguiente?
Dale a la cabecera o al contenedor que tiene el menú un z-index más alto que el de las secciones que van detrás, con ambos posicionados. Si el contenedor tiene un transform o una opacity, recuerda que es un contexto propio, así que el z-index debe ir en ese contenedor, no en el menú.
¿Es seguro un z-index negativo?
Es válido, pero el elemento pasa detrás del fondo de su contexto de apilamiento. Si el padre no tiene contexto, eso puede significar quedar detrás del fondo de la página e invisible. Añade isolation: isolate al padre para mantenerlo dentro.
Cómo funciona el orden de pintado
Dentro de un contexto de apilamiento, el navegador pinta en un orden fijo: el propio fondo del contexto, luego los hijos con z-index negativo, después el contenido de bloque normal, los floats, el contenido en línea, los elementos posicionados con z-index auto o 0 en el orden del código y, por último, los z-index positivos de menor a mayor.
Un contexto hijo se pinta como una sola unidad en la posición de su padre dentro de esa lista. Todo lo que hay dentro se ordena solo respecto a sus hermanos. Esa es toda la razón por la que un 9999 dentro de una tarjeta con z-index: 1 pierde frente a un vecino con z-index: 2.
Una rutina de depuración
Primero confirma que es un problema de apilamiento: si el elemento se corta en un borde recto, busca más bien un overflow en un ancestro. Después sube desde el elemento oculto en DevTools y revisa los estilos calculados de cada ancestro buscando los desencadenantes que aparecen en esta página.
Las DevTools de Chromium tienen un panel Layers y Edge tiene una 3D View que muestran visualmente las capas compuestas. Cuando encuentres el ancestro que forma el contexto, sube ese ancestro, quita el desencadenante o renderiza la pieza flotante fuera de él.
Todo lo que crea un contexto de apilamiento
Basado en la referencia de MDN sobre contextos de apilamiento. Basta con una sola condición.
Desencadenantes de contextos de apilamiento
Propiedad o estado
Condición
Elemento raíz
html es siempre el contexto de apilamiento raíz
position: absolute o relative
Solo con un z-index distinto de auto
position: fixed o sticky
Siempre, no hace falta z-index
Hijo de flex o grid
Con un z-index distinto de auto, aunque position sea static
container-type: size o inline-size
Cualquier elemento que sea un contenedor de consultas de tamaño
opacity por debajo de 1
Incluido opacity: 0.99
Cualquier valor distinto de normal
transform, scale, rotate, translate
Cualquier valor distinto de none
filter o backdrop-filter
Cualquier valor distinto de none
Cualquier valor distinto de none
Cualquier valor distinto de none
mask, mask-image, mask-border
Cualquier valor distinto de none
isolation: isolate
Pensado exactamente para esto, sin efectos visuales secundarios
Indicar cualquier propiedad que crearía un contexto de apilamiento al definirse
layout, paint, o una forma abreviada que los incluya (strict, content)
Capa superior
Diálogo modal abierto, popover, elemento a pantalla completa y su ::backdrop
La trampa y las soluciones
Un z-index 9999 que sigue perdiendo
La tarjeta azul es un contexto con z-index 1. Su tooltip tiene 9999, pero solo se compara con lo que hay dentro de la tarjeta, así que la caja naranja con z-index 2 lo tapa.
isolation: isolate mantiene dentro una capa negativa
Sin isolate, la decoración con z-index: -1 caería detrás del fondo de la sección y desaparecería. Con él, la sección es su propio contexto.
Cabecera sticky con un menú desplegable
La cabecera es sticky, así que ya es un contexto. Dale un z-index por encima del contenido y el menú de dentro hereda esa capa. No hacen falta números enormes.
Contenido normal
Tarjetas que se elevan al pasar el ratón, cabeceras de tabla sticky
Menús, listas de autocompletado
Cabecera sticky del sitio
Fondo de un panel lateral
Modales propios (el dialog nativo usa en su lugar la capa superior)
Notificaciones que deben quedar por encima de todo
Laboratorio de apilamiento con vista 3D despiezada
z-index de la cabecera
z-index de la tarjeta (o auto)
z-index del menú desplegable
z-index del banner
Desencadenante de contexto en la tarjeta
Propiedad extra en la tarjeta
Vista 3D despiezada (separa las capas girándolas)
Capas separadas: más arriba significa pintada más tarde
Vista plana, CSS real
Cabecera z {z}
Tarjeta z {z}
Menú desplegable z {z}
Banner z {z}
(dentro de la tarjeta)
por encima del banner
por debajo del banner
La tarjeta forma un contexto de apilamiento ({why}). El {d} del menú desplegable solo cuenta dentro de la tarjeta, así que queda {pos} porque la tarjeta también lo está.
La tarjeta no es un contexto de apilamiento, así que el menú desplegable compite directamente: {d} frente al {b} del banner. Queda {pos}.
CSS de esta configuración
Copiar CSS
Prueba: tarjeta z auto, menú desplegable 9999, y luego elige transform. Una sola propiedad atrapa el menú.