Contexto de apilamiento CSS (Stacking Context)

¿Alguna vez sentiste que CSS te engañaba? Pones z-index: 9999 y tu elemento sigue detrás de otro. No te engañaron: simplemente no entendías el stacking context.


¿Qué es el stacking context?

El contexto de apilamiento es un grupo de elementos que se renderizan juntos como una sola unidad. Cada elemento HTML crea su propio contexto, y todos sus hijos vivirán dentro de ese contexto.

Regla clave: Un elemento hijo nunca puede estar encima de elementos que están fuera de su contexto de apilamiento, sin importar qué z-index tenga.


¿Qué crea un stacking context?

Estos son los principales creadores de stacking context:

1. position con z-index

.elemento {
  position: relative;
  z-index: 1; /* Crea stacking context */
}

2. opacity menor a 1

.caja {
  opacity: 0.9; /* Crea stacking context */
}

3. transform

.caja {
  transform: translateX(10px); /* Crea stacking context */
}

4. filter

.caja {
  filter: blur(2px); /* Crea stacking context */
}

5. position: fixed

.overlay {
  position: fixed; /* Crea stacking context */
  z-index: 9999;
}

6. isolation: isolate

.componente {
  isolation: isolate; /* Crea stacking context */
}

7. Elementos flex/grid con z-index

.container {
  display: flex;
}

.item {
  z-index: 10; /* También crea contexto si el padre es flex/grid */
}

Ejemplo visual del problema

<div class="tarjeta" style="z-index: 1">
  <div class="badge" style="z-index: 9999">
    Nuevo
  </div>
</div>

<div class="modal" style="z-index: 100">
  Contenido
</div>

¿Qué sucede?

  • El badge tiene z-index: 9999
  • Pero su padre tarjeta tiene z-index: 1
  • El badge nunca podrá estar encima del modal con z-index: 100
┌─────────────────────────────────┐
│  .modal (z-index: 100)          │
│  ┌─────────────────────────────┐│
│  │ Esta es la barrera          ││
│  │ que el badge no puede       ││
│  │ cruzar                      ││
│  └─────────────────────────────┘│
└─────────────────────────────────┘

┌─────────────────────┐
│ .tarjeta (z-index: 1) │
│  ┌─────────────┐     │
│  │ .badge      │     │
│  │ z-index:9999│ ← No puede salir
│  │ "Nuevo"     │     │
│  └─────────────┘     │
└─────────────────────┘

¿Por qué existe el stacking context?

El stacking context existe por razones de rendimiento y predictibilidad:

  1. Rendimiento: El navegador no necesita calcular la posición de cada elemento contra todos los demás.

  2. Predictibilidad: Permite crear componentes aislados que no afecten el resto de la página.

  3. Componentes: Facilita crear elementos como modales, tooltips que funcionan independientemente.


Cómo resolver problemas de stacking context

Truco 1: Usa position: fixed para overlays

.modal {
  position: fixed; /* Crea su propio contexto */
  z-index: 9999;
}

Truco 2: Portales (React/Vue)

// Renderiza el modal fuera de la jerarquía del componente
createPortal(<Modal />, document.body);

Truco 3: Elimina propiedades problemáticas

/* ❌ Crea contexto */
.bloque {
  opacity: 0.95;
}

/* ✅ Alternativa */
.bloque {
  background: rgba(255, 255, 255, 0.95);
}

Truco 4: Usa isolation: isolate con cuidado

.componente-aislado {
  isolation: isolate;
  /* Los hijos ahora están en un contexto separado */
  /* Pero esto también limita al componente */
}

Orden de apilamiento por defecto

Cuando no hay z-index, el navegador apila en este orden:

  1. Fondo y bordes de elementos de bloque
  2. Elementos flotantes (float)
  3. Contenido en línea (texto e imágenes)
  4. Elementos posicionados (con z-index positivo)
  5. Elementos con z-index negativo
/* Este elemento aparece DETRÁS del contenido normal */
.footer {
  position: relative;
  z-index: -1;
}

Checklist para debuggear stacking context

  • ¿El elemento tiene position distinta de static?
  • ¿El padre tiene z-index que lo limite?
  • ¿Hay opacity, transform o filter en el padre?
  • ¿Usas position: fixed para overlays?
  • ¿Necesitas un portal para salir del contexto?

Artículos relacionados


: El stacking context es como una prisión para elementos hijos. No puedes salir, solo dentro de las paredes de tu padre.