Si alguna vez has configurado position: sticky en un menú lateral o en una tabla de contenido y has visto cómo simplemente… no se queda fijo, no estás solo.

Por qué CSS position: sticky deja de funcionar (Y cómo el overflow en html/body lo rompe)

En este artículo repasaré un caso real con el que me topé, incluyendo:

  • El motivo real por el cual falla el posicionamiento sticky
  • Cómo diagnosticarlo correctamente en DevTools
  • Por qué el overflow en html y body era el culpable, y cómo solucionarlo

con un desglose paso a paso reproducible.


El malentendido común sobre position: sticky

Es posible que tengas un CSS que parezca perfectamente correcto, así:

css
.category-toc {
  position: sticky;
  top: 100px;
}

Y aun así te encuentres con las mismas quejas:

  • Se ha establecido position: sticky, pero no pasa nada
  • Se ha definido top
  • Ningún overflow: hidden en ningún elemento padre… o eso crees

Si aún sigue sin fijarse, es muy probable que la declaración en sí esté bien, pero que algo estructural la esté anulando silenciosamente.


Qué comprobar primero (diagnosticando con DevTools)

Abre las Herramientas de desarrollador en Chrome (o Edge), ve a la pestaña Console (Consola) y ejecuta:

js
const el = document.querySelector('.category-toc');

getComputedStyle(el).position
getComputedStyle(el).top
getComputedStyle(el).overflow

[!NOTE] Si es la primera vez que pegas algo en la consola, es posible que tengas que escribir «allow pasting» (permitir pegar) manualmente antes de que Chrome te permita pegar código.

Qué aspecto tiene un resultado correcto

txt
position: "sticky"
top: "100px"
overflow: "visible"

Si estos valores son correctos, la declaración sticky en sí misma no es el problema.

Si sigue sin fijarse después de confirmar esto, el siguiente sospechoso está en otra parte.

La causa raíz más común: overflow en html / body

En mi caso, el culpable fueron los ajustes de overflow en html y body.

Al comprobar la consola se reveló algo como esto:

js
{
  scrollingElement: 'html',
  htmlOverflow: 'hidden auto',
  bodyOverflow: 'auto'
}

Lo cual significaba efectivamente que:

  • html: overflow-x: hidden; overflow-y: auto
  • body: overflow: auto

En otras palabras, había dos contenedores de desplazamiento independientes activos a la vez.

Por qué el overflow en html/body rompe el sticky

position: sticky calcula su posición en relación con:

  • El ancestro con desplazamiento más cercano, o
  • La ventana gráfica (viewport), si no hay ninguno

Pero cuando:

  • html tiene desplazamiento
  • body también tiene desplazamiento
  • Y hay un elemento contenedor (wrapper) por encima de eso

…el navegador no puede determinar de forma fiable a qué contenedor debe anclarse el elemento sticky, y el resultado práctico es un elemento que parece ignorar por completo el posicionamiento sticky.

La solución: deja que html gestione el desplazamiento y devuelve body al flujo normal

La solución más fiable es la siguiente:

css
html {
  overflow-x: hidden;
  overflow-y: auto;
}

body {
  overflow: visible;
}

Puntos clave

  • Consolida el desplazamiento vertical únicamente en html
  • No establezcas overflow: auto en body
  • Mantener overflow-x: hidden para evitar el desplazamiento horizontal es correcto

En el momento en que se aplicó este cambio, el elemento sticky que se había negado a funcionar comenzó a funcionar de inmediato.


Pruébalo primero en vivo en la consola

Antes de tocar tu CSS real, puedes probar este comportamiento de forma temporal en la consola:

js
document.documentElement.style.overflowY = 'auto';
document.documentElement.style.overflowX = 'hidden';
document.body.style.overflow = 'visible';

Si el elemento sticky empieza a funcionar después de ejecutar esto, habrás confirmado que el overflow es la causa.

Cuidado con estas regresiones comunes

El posicionamiento sticky puede volver a romperse si aparece alguno de los siguientes elementos más adelante en tu código:

  • Implementaciones de modales que dejan html { overflow: hidden } permanentemente
  • Código de diseño que establece body { overflow: auto } por razones ajenas
  • Un contenedor height: 100vh combinado con su propio control de overflow

Si necesitas bloquear el desplazamiento mientras un modal está abierto, es más seguro mantener overflow: auto como estado predeterminado y cambiar a hidden únicamente mientras el modal esté activo:

css
html {
  overflow-y: auto;
  overflow-x: hidden;
}

.modal-open html {
  overflow: hidden;
}

Resumen: qué comprobar cuando un elemento sticky no se fija

  • No des por hecho que todo está bien solo porque position y top tienen el aspecto correcto
  • Comprueba overflow en html y body, no solo en el elemento padre inmediato
  • Asegúrate de que solo hay un contenedor de desplazamiento activo en la página

La mayoría de las veces, los problemas de posicionamiento sticky se deben a desde dónde se está desplazando realmente la página y no a un error en cómo se ha escrito la propiedad sticky en sí.

Esperamos que esto le ahorre a alguien más la misma sesión de depuración.