Maquetación Web Dinámica / Posicionamiento y capas
z-index y stacking contexts: por qué tu 9999 no funciona
Todo desarrollador ha vivido este momento: un dropdown tapado por otra
cosa, le pones z-index: 9999... y nada. Subes a 999999. Nada. El problema
nunca fue el número — fue el contexto. Hoy entiendes los stacking contexts
y no vuelves a perder esa pelea.
El apilamiento natural
Sin z-index, el orden de capas ya existe: los elementos posteriores en el HTML pintan encima de los anteriores, y los posicionados (no static) pintan encima de los no posicionados. Muchos "problemas de z-index" se resuelven simplemente moviendo un elemento al final del HTML.
z-index: el número de piso
Mayor número, más arriba. Dos disciplinas profesionales: (1) z-index solo
actúa en elementos posicionados (o ítems de flex/grid); (2) usa una escala
corta y documentada — 1 (elevado), 10 (dropdown), 100 (header),
1000 (modal) — no subastas de nueves.
El stacking context: la trampa
Aquí el concepto que explica el misterio. Ciertas propiedades crean un stacking context: una burbuja de apilamiento donde los z-index de los hijos SOLO compiten entre ellos. Frente al exterior, toda la burbuja es UNA capa con el z-index de su creador.
Crean stacking context, entre otros: un elemento posicionado CON z-index,
opacity menor a 1, transform, filter — ojo con estas tres últimas:
las usarás muchísimo en los módulos de animación, y crean burbujas sin
avisar.
<div class="padre-a">padre A (z-index: 1)
<div class="hijo">hijo con z-index: 9999</div>
</div>
<div class="padre-b">padre B (z-index: 2) — gano yo, aunque el hijo de A tenga 9999</div>body { font-family: system-ui; padding: 24px; font-size: 13px; }
.padre-a { position: relative; z-index: 1; background: #ede9fe; border: 2px solid #6d28d9; border-radius: 10px; padding: 12px; width: 260px; color: #4c1d95; font-weight: 600; }
.hijo { position: absolute; z-index: 9999; top: 40px; left: 40px; background: #b45309; color: white; border-radius: 8px; padding: 14px; width: 200px; }
.padre-b { position: relative; z-index: 2; background: #0f172a; color: white; border-radius: 10px; padding: 20px; width: 280px; margin-top: -30px; margin-left: 120px; font-weight: 600; }Ahí está el bug de tu futuro, en vivo: el hijo con z-index: 9999 pierde
contra un simple z-index: 2 — porque su 9999 solo vale DENTRO de la
burbuja del padre A, y la burbuja entera es "capa 1" frente al padre B.
Tu dropdown (z-index: 9999) sigue tapado por el header (z-index: 100). El dropdown vive en una tarjeta con transform: scale(1.02). ¿La causa?
Mini-reto
Reproduce el bug a propósito: tarjeta con transform: scale(1.01), hijo
absolute con z-index gigante, y un vecino con z-index 2 que lo tape. Luego
arréglalo por las tres vías del protocolo. Diagnosticado una vez en frío,
lo resolverás en segundos cuando te pase en caliente.
Qué sigue
Última pieza teórica del módulo: la sintaxis moderna que abrevia todo lo que llevas escrito (inset) y el debate del centrado absoluto — más su reemplazo moderno.