z-index dropdown menú: problemas y soluciones

El clásico: Tienes un menú desplegable que debería aparecer encima de todo, pero aparece detrás de las tarjetas de tu contenido. 📦

Aquí tienes la solución.


¿Por qué el dropdown queda atrás?

El problema común

<nav class="navbar" style="z-index: 10">
  <div class="menu-container">
    <button>Menú</button>
    <div class="dropdown">
      <!-- Este dropdown NO puede salir del navbar -->
      Opciones...
    </div>
  </div>
</nav>

<main style="z-index: 1">
  <!-- Las tarjetas están aquí -->
  <div class="card">Producto 1</div>
  <div class="card">Producto 2</div>
</main>

El problema: El dropdown está limitado por el z-index: 10 del navbar.


Soluciones probadas

Solución 1: Sube el z-index del padre

La solución más simple:

.navbar {
  position: relative;
  z-index: 1000; /* Suficientemente alto */
}

.dropdown {
  position: absolute;
  z-index: 1001; /* Más alto que el navbar */
}

Solución 2: Usa position: fixed para el dropdown

Si el menú debe estar siempre encima:

.dropdown {
  position: fixed;
  z-index: 9999;
  top: 100%;
  left: 0;
}

Precaución: Esto puede causar problemas con scroll en páginas largas.


Solución 3: Mueve el dropdown fuera del flujo

Usa un portal para renderizar el dropdown en document.body:

React:

import { createPortal } from 'react-dom';

function Dropdown({ isOpen, children }) {
  if (!isOpen) return null;
  
  return createPortal(
    <div className="dropdown">{children}</div>,
    document.body
  );
}

Vanilla JS:

// Mover el dropdown a body cuando se abre
document.querySelector('.dropdown').appendChild(document.body);

Solución 4: Evita overflow: hidden en contenedores

/* ❌ Este corta el dropdown */
.menu-container {
  overflow: hidden;
}

/* ✅ Usa overflow: auto o visible */
.menu-container {
  overflow: visible;
}

Ejemplo completo: Navbar con dropdown

.navbar {
  position: relative;
  z-index: 100;
  background: white;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.menu-trigger {
  position: relative;
  padding: 0.5rem 1rem;
  cursor: pointer;
}

.dropdown-menu {
  position: absolute;
  z-index: 200; /* Mayor que el navbar */
  top: 100%;
  left: 0;
  min-width: 200px;
  background: white;
  box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  border-radius: 4px;
}

/* Si hay contenido que lo supera */
.main-content {
  /* No pongas z-index aquí */
}
<nav class="navbar">
  <div class="menu-trigger">
    Menú
    <div class="dropdown-menu">
      <a href="#">Opción 1</a>
      <a href="#">Opción 2</a>
      <a href="#">Opción 3</a>
    </div>
  </div>
</nav>

<main class="main-content">
  <!-- Las tarjetas pasan DETRÁS del dropdown -->
  <div class="card">Producto</div>
</main>

Problema: Sticky header + Dropdown

Si tienes un header sticky:

.sticky-header {
  position: sticky;
  z-index: 100;
}

.dropdown {
  z-index: 200; /* Debe ser mayor que el header */
}

Checklist para dropdowns

  • ¿El navbar/header tiene z-index?
  • ¿El dropdown tiene mayor z-index que su padre?
  • ¿Hay overflow: hidden cortando el dropdown?
  • ¿Usaste position: fixed si es necesario?

Artículos relacionados


: El dropdown necesita espacio para respirar. Dale el z-index que merece.