El Problema del 100vh en Móviles: Guía Completa 2026 para Solucionarlo

Inicio » CSS-Maquetación » El Problema del 100vh en Móviles: Guía Completa 2026 para Solucionarlo
Contenidos ocultar

El Problema del 100vh en Móviles: Guía Completa 2026 para Solucionarlo

¿Alguna vez has creado una sección con `height: 100vh` que funciona perfecto en desktop, pero en móvil tiene un scroll extra no deseado? No estás solo. Este es uno de los problemas CSS más frustrantes para desarrolladores web, y lleva causando dolores de cabeza desde 2015.

En esta guía completa voy a explicarte por qué ocurre, todas las soluciones disponibles, y cuál es el futuro de las unidades viewport en CSS.

¿Qué es exactamente el problema del 100vh?

El problema visual

Imagina esta situación:

«`css .hero { height: 100vh; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); } «`

En desktop se ve perfecto: la sección ocupa exactamente el 100% de la altura visible.

Pero en móvil (especialmente iOS Safari), pasa esto:

1. La sección es MÁS ALTA que la pantalla visible 2. Aparece un scroll vertical no deseado 3. El contenido se «corta» o necesita scroll para verse completo

¿Por qué pasa esto?

El problema no es un «bug» sino una decisión de diseño de los navegadores.

En móviles, la barra de direcciones (URL bar) es dinámica:

Desplazada hacia arriba: La barra ocupa espacio – Desplazada hacia abajo: La barra se oculta, ganando espacio

¿Qué significa 100vh? – `100vh` = 100% de la altura del viewport COMPLETO – Esto incluye el espacio donde está la barra de direcciones – Pero el usuario solo ve el viewport VISIBLE

El resultado: `100vh` > altura visible → scroll no deseado.

Historia del problema

Este comportamiento fue documentado por primera vez por Nicolas Hoizey en 2015. Se abrió un issue en el WebKit Bug Tracker, pero fue marcado como «intended behavior» (comportamiento intencional).

Navegadores afectados: – ✅ iOS Safari (todas las versiones) – ⚠️ Chrome para Android (parcialmente) – ⚠️ Firefox para Android (parcialmente)

Solución 1: CSS con `-webkit-fill-available` (Recomendada)

Esta es la solución más simple y efectiva para la mayoría de casos.

Código base

«`css html { height: -webkit-fill-available; }

body { min-height: 100vh; min-height: -webkit-fill-available; } «`

Versión con fallback (más robusta)

«`css html { height: -webkit-fill-available; }

body { margin: 0; padding: 0; min-height: 100vh; }

/* Solo Safari móvil */ @supports (-webkit-touch-callout: none) { body { min-height: -webkit-fill-available; } } «`

¿Por qué funciona?

`-webkit-fill-available` es una propiedad propietaria que: – Ocupa el espacio DISPONIBLE en el contenedor – Ignora la barra de direcciones en Safari – Usa solo el viewport visible real

Limitaciones

– ⚠️ No es estándar (aunque todos los navegadores la soportan) – ⚠️ Puede tener comportamientos inesperados en contenedores anidados – ⚠️ Requiere `@supports` para evitar afectar otros navegadores

Solución 2: JavaScript con CSS Variables (Más flexible)

Si necesitas control total o animaciones, esta solución es ideal.

Paso 1: CSS con variable

«`css :root { –vh: 1vh; /* Fallback */ }

body { margin: 0; padding: 0; }

.hero { height: 100vh; height: calc(var(–vh, 1vh) * 100); } «`

Paso 2: JavaScript que calcula la altura real

«`javascript // Función que calcula y actualiza la variable CSS const setVH = () => { const vh = window.innerHeight * 0.01; document.documentElement.style.setProperty(‘–vh’, `${vh}px`); };

// Ejecutar al cargar setVH();

// Actualizar en resize y orientación window.addEventListener(‘resize’, setVH); window.addEventListener(‘orientationchange’, setVH); «`

Versión mejorada con debounce

«`javascript const setVH = () => { const vh = window.innerHeight * 0.01; document.documentElement.style.setProperty(‘–vh’, `${vh}px`); };

// Debounce para evitar demasiados cálculos let resizeTimer; window.addEventListener(‘resize’, () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(setVH, 100); });

// Orientación cambio (disparado inmediatamente) window.addEventListener(‘orientationchange’, () => { setVH(); }); «`

Ventajas de esta solución

Control total: Sabes exactamente qué altura se usa ✅ Animaciones: Puedes animar transiciones de altura ✅ Cross-browser: Funciona en todos los navegadores ✅ Responsive: Se adapta en tiempo real

Desventajas

❌ Requiere JavaScript ❌ Pequeño delay en cálculo (milisegundos) ❌ Necesita debounce para performance

Solución 3: PostCSS con autoprefixer (Automatizada)

Si usas un build process, puedes automatizar la solución.

Instalar dependencias

«`bash npm install postcss postcss-viewport-height-correction –save-dev «`

Configuración postcss.config.js

«`javascript module.exports = { plugins: [ require(‘postcss-viewport-height-correction’)({ userAgent: navigator.userAgent, // Opciones adicionales // onlyMobile: true, // force: true }), ], }; «`

Resultado

El plugin automáticamente convierte:

«`css .hero { height: 100vh; } «`

En:

«`css .hero { height: 100vh; height: -webkit-fill-available; } «`

Casos de Uso Comunes

Hero section con imagen de fondo

«`css .hero { height: 100vh; height: -webkit-fill-available; background-image: url(‘hero-bg.jpg’); background-size: cover; background-position: center; display: flex; align-items: center; justify-content: center; } «`

Modal pantalla completa

«`css .modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; height: 100vh; height: -webkit-fill-available; overflow: auto; } «`

Slide tipo carrusel

«`css .slide { height: 100vh; height: calc(var(–vh, 1vh) * 100); scroll-snap-align: start; }

.carousel { height: 100vh; height: calc(var(–vh, 1vh) * 100); scroll-snap-type: y mandatory; overflow-y: scroll; } «`

El Futuro: Nuevas Unidades Viewport

CSS está evolucionando para resolver este problema de forma nativa.

Nuevas unidades propuestas

| Unidad | Significado | |——–|————-| | `dvh` | Dynamic Viewport Height (viewport con barras dinámicas) | | `svh` | Small Viewport Height (viewport con barras visibles) | | `lvh` | Large Viewport Height (viewport con barras ocultas) |

Soporte actual (2026)

«`css .hero { /* Futuro: cuando el soporte sea universal */ height: 100dvh; /* Dynamic viewport height */

/* Fallback actual */ height: -webkit-fill-available; } «`

Estado de soporte: – ✅ Chrome 108+ – ✅ Edge 108+ – ✅ Firefox 101+ – ⚠️ Safari (en desarrollo)

Estrategia de implementación

«`css .hero { /* Fallback para navegadores antiguos */ height: 100vh;

/* Solución actual Safari móvil */ height: -webkit-fill-available;

/* Futuro: unidades dinámicas */ height: 100dvh; } «`

Troubleshooting: Problemas Comunes

Problema 1: Scroll horizontal no deseado

Causa: Content overflow + viewport height

Solución: «`css html, body { overflow-x: hidden; width: 100%; }

.hero { max-width: 100%; overflow: hidden; } «`

Problema 2: La barra de navegación se superpone

Causa: `position: fixed` sin considerar el viewport

Solución: «`css .navbar { position: fixed; top: 0; left: 0; right: 0; height: 60px; z-index: 1000; }

.hero { height: calc(100vh – 60px); height: calc(-webkit-fill-available – 60px); padding-top: 60px; } «`

Problema 3: No funciona en landscape

Causa: Orientación cambia el viewport

Solución (JavaScript): «`javascript const setVH = () => { const vh = window.innerHeight * 0.01; document.documentElement.style.setProperty(‘–vh’, `${vh}px`); };

window.addEventListener(‘orientationchange’, () => { setTimeout(setVH, 100); // Delay para que el navegador recalcule }); «`

Checklist para Desarrollo

Antes de deployar, verifica:

Probado en iOS Safari (iPhone) Probado en Chrome Android Probado en landscape y portrait Probado con barra de direcciones visible/oculta Sin scroll horizontal no deseado Las animaciones funcionan correctamente El contenido es accesible en todas las pantallas

Herramientas Útiles

Test en dispositivo real

Xcode + iOS Simulator: – Simula iPhone/iPad – Testing preciso de Safari iOS – Debug con Safari DevTools

BrowserStack: – Testing en dispositivos reales – Múltiples navegadores – Capturas de pantalla

CodePen para pruebas rápidas

«`html

Test 100vh

«`

Conclusión

El problema del `100vh` en móviles es uno de esos casos donde la teoría CSS (`100vh` = altura completa) choca con la práctica (barras de direcciones dinámicas).

Resumen de soluciones:

| Solución | Cuando usarla | |———-|—————| | `-webkit-fill-available` | Casos simples, sin JS | | CSS Variables + JS | Control total, animaciones | | PostCSS plugin | Build process automatizado | | `100dvh` (futuro) | Cuando el soporte sea universal |

Mi recomendación: Para 2026, usa `-webkit-fill-available` con fallback, y empieza a probar `100dvh` en proyectos nuevos.

El futuro de CSS está prometiendo soluciones nativas, pero mientras tanto, estas técnicas te ahorrarán horas de debugging.

¿Sigues teniendo problemas con el 100vh en tu proyecto? Déjame un comentario con tu caso específico y te ayudo a diagnosticarlo.

¿Necesitas ayuda con CSS responsive? Echa un vistazo a mis otros tutoriales de CSS maquetación.

Deja un comentario