Unidades CSS: cuándo usar px, rem, em, vw y vh bien

Las unidades CSS son la fuente de la mitad de los líos con el diseño responsive. Pones px donde tocaba rem, o 100vh y la página se corta en el móvil. La duda de siempre es la misma: ¿px, %, em, rem, vw o vh?

Aquí va la guía que me habría gustado tener cuando empecé. No es un tutorial de media queries ni de «cómo hacer una web responsive». Es lo anterior a todo eso: qué mide cada unidad, cuándo usar cada una y los errores que casi todos cometemos al principio. Con ejemplos de código y las unidades nuevas (dvh, svh, lvh) que arreglan viejos dolores de cabeza.

Absolutas vs relativas: la diferencia que lo cambia todo

Todas las unidades CSS caben en dos grupos. Una unidad absoluta vale siempre lo mismo, pase lo que pase. Una unidad relativa se calcula a partir de otra cosa: el tamaño de fuente, el tamaño del elemento padre o el del viewport.

Regla mental rápida: si quieres que algo se adapte a la pantalla o al zoom del usuario, usa una unidad relativa. Si quieres que algo mida exactamente lo mismo siempre, usa px. La mayoría de errores de responsive nacen de fijar en píxeles lo que debería escalar.

px: la unidad absoluta (y cuándo te conviene)

El píxel CSS es la unidad absoluta de referencia. No equivale a un píxel físico de la pantalla: por definición, 1px es 1/96 de pulgada. El navegador ya se encarga de traducirlo a los píxeles reales del dispositivo.

El px tiene mala fama, pero no es el enemigo. Es la mejor opción para cosas que no deben escalar: el grosor de un borde (1px), el radio de una esquina, una sombra o el tamaño fijo de un icono decorativo. Ahí un borde de 1px es exactamente lo que quieres.

.tarjeta {
  border: 1px solid #ddd;   /* px: no debe crecer con el zoom */
  border-radius: 8px;       /* px: detalle fino y constante */
  box-shadow: 0 2px 6px rgba(0,0,0,.1);
}

El problema aparece cuando fijas en px el tamaño del texto o el ancho de un contenedor. Ahí pierdes accesibilidad y adaptabilidad. Para eso están las unidades relativas.

em y rem: la diferencia que casi nadie explica bien

Aquí está la diferencia entre em y rem, que causa más confusión de la que debería. Las dos son relativas al tamaño de fuente. Cambia una cosa: respecto a qué.

  • rem es relativo al tamaño de fuente del elemento raíz (<html>). Si la raíz mide 16px, 1rem = 16px en toda la página. Da igual dónde esté.
  • em es relativo al tamaño de fuente del propio elemento. Y para la propiedad font-size, se calcula sobre la fuente del elemento padre. Eso hace que los em se acumulen si los anidas.

El efecto acumulativo del em es lo que pilla a todo el mundo. Mira este caso: cada nivel multiplica al anterior.

html { font-size: 16px; }

.caja  { font-size: 1.5em; }  /* 16 * 1.5 = 24px */
.caja .caja { font-size: 1.5em; }  /* 24 * 1.5 = 36px, se acumula */

/* Con rem no hay sorpresas: */
.titulo { font-size: 1.5rem; }  /* siempre 24px, mida lo que mida el padre */

Mi regla: usa rem para el tamaño de fuente y para espaciados que deban respetar la preferencia del usuario. Deja em para valores que deban escalar con el texto de ese componente concreto: el padding de un botón que crece si el botón usa una fuente más grande, por ejemplo.

.boton {
  font-size: 1rem;          /* rem: coherente con el resto de la web */
  padding: 0.6em 1.2em;     /* em: el relleno crece con SU propia fuente */
}

Truco de accesibilidad: si defines el texto en rem, cuando el usuario sube el tamaño de fuente en su navegador, toda la web escala con él. Con px se queda clavado e ignora esa preferencia.

% en CSS: relativo al padre

El porcentaje se calcula respecto al elemento padre, pero respecto a qué dimensión del padre depende de la propiedad. Un width: 50% es la mitad del ancho del contenedor. Un height: 50% es la mitad de su alto (y solo funciona si el padre tiene un alto definido, un detalle que da muchos quebraderos).

El % es tu unidad para anchos fluidos dentro de un layout: columnas, imágenes que ocupan el 100% de su contenedor, contenedores que se reparten el espacio. Cuando el «padre» que te interesa es la ventana entera, ahí entran vw y vh.

vw y vh: qué es cada uno

Estas dos son las que más buscas y las que más se confunden. Van referidas al viewport, es decir, al área visible de la ventana del navegador, no al elemento padre.

  • vw (viewport width): 1vw es el 1% del ancho del viewport. 100vw es el ancho completo de la ventana.
  • vh (viewport height): 1vh es el 1% del alto del viewport. Así que qué es vh en CSS se responde fácil: la centésima parte de la altura de la ventana.

El uso estrella de vw vh en CSS es la sección «a pantalla completa»: un hero que ocupe toda la ventana al cargar. Con vh lo consigues sin trucos de JavaScript.

.hero {
  min-height: 100vh;   /* ocupa toda la altura visible */
  width: 100vw;        /* cuidado: incluye el ancho de la barra de scroll */
}

Dos avisos. 100vw incluye el ancho de la barra de scroll vertical, así que en escritorio puede provocar scroll horizontal; muchas veces es mejor width: 100%. Y 100vh en el móvil no mide lo que crees: sigue leyendo.

dvh, svh y lvh: el arreglo del 100vh en móvil

El clásico problema: pones height: 100vh y en el móvil el contenido queda tapado por la barra de direcciones, o aparece un hueco cuando esa barra se oculta al hacer scroll. Pasaba porque vh se calcula sobre el viewport «grande», ignorando las barras dinámicas del navegador.

Para resolverlo llegaron las unidades de viewport dinámico. Miden lo mismo que vh, pero según el estado de la interfaz del navegador:

  • svh (small viewport height): la altura más pequeña, contando con las barras del navegador visibles.
  • lvh (large viewport height): la altura más grande, asumiendo las barras ocultas.
  • dvh (dynamic viewport height): se ajusta en tiempo real según se muestran u ocultan esas barras.
.hero {
  min-height: 100vh;   /* fallback para navegadores antiguos */
  min-height: 100dvh;  /* alto real en móvil, sin cortes ni huecos */
}

Existen también sus versiones de ancho (svw, lvw, dvw), aunque el ancho suele variar poco. La buena práctica es dejar 100vh como fallback y encima 100dvh; los navegadores modernos usan el segundo y los antiguos se quedan con el primero. Puedes confirmar el soporte y la definición en la documentación de unidades de longitud de MDN.

Tabla: para qué sirve cada unidad CSS

UnidadRelativa aÚsala para
pxNada (absoluta)Bordes, radios, sombras, iconos fijos
remFuente de la raízTamaño de texto, espaciados consistentes
emFuente del propio elementoPadding/margin que escala con su texto
%Elemento padreAnchos fluidos, columnas, imágenes
vwAncho del viewportAnchos a pantalla completa
vhAlto del viewportSecciones a pantalla completa (escritorio)
dvh / svh / lvhAlto del viewport dinámicoPantalla completa en móvil sin cortes

clamp() para tipografía fluida

Hasta aquí has elegido una unidad por valor. La función clamp() te deja combinar varias y crear tamaños que se adaptan solos, sin media queries. Su sintaxis es clamp(mínimo, valor preferido, máximo): el navegador usa el valor preferido, pero nunca baja del mínimo ni sube del máximo.

h1 {
  /* nunca menos de 1.8rem, ideal 5vw, nunca más de 3.5rem */
  font-size: clamp(1.8rem, 5vw, 3.5rem);
}

Ese 5vw del centro hace que el título crezca con la pantalla, y los topes en rem evitan que se quede diminuto en el móvil o gigante en un monitor grande. Es la forma más limpia de tipografía fluida hoy.

Sus primas min() y max() siguen la misma idea con dos valores. width: min(90%, 1200px) dice «el 90% del contenedor, pero como mucho 1200px». Muy útil para contenedores que no deben pasarse de ancho. Tienes la referencia completa de clamp() en MDN.

Cuándo usar rem o px: reglas rápidas

Si solo te llevas una chuleta de todo el artículo, que sea esta. Resuelve la duda de cuándo usar rem o px y el resto en un vistazo:

  • Textorem (respeta el zoom y la preferencia del usuario).
  • Espaciados (padding, margin, gap) → rem para consistencia; em si deben escalar con el texto del componente.
  • Bordes, radios, sombraspx.
  • Anchos dentro del layout% o min().
  • Secciones a pantalla completadvh (con vh de fallback).
  • Tamaños que deban fluirclamp() mezclando rem y vw.

Errores comunes con las unidades CSS

  • Fijar el texto en px. Rompe la accesibilidad: quien sube el tamaño de fuente en su navegador se queda igual. Usa rem.
  • Anidar em sin darte cuenta. Como se acumula, el texto de un componente anidado se va disparando. Si no lo controlas, cambia a rem.
  • 100vw provocando scroll horizontal. Incluye la barra de scroll. En anchos, casi siempre prefieres 100%.
  • 100vh en el móvil. El contenido queda tapado por la barra del navegador. Usa 100dvh.
  • Tamaños de fuente en vw a secas. Sin topes, el texto se vuelve ilegible en pantallas pequeñas. Envuélvelo en clamp().

Con esto ya sabes elegir la unidad correcta. El siguiente paso natural es maquetar con ellas. Te dejo tres lecturas para seguir el hilo.

Preguntas frecuentes

¿Qué es vh en CSS?

vh es una unidad relativa al alto del viewport: 1vh equivale al 1% de la altura visible de la ventana. Por eso 100vh ocupa toda la altura de la pantalla. En móvil conviene usar dvh para evitar que la barra del navegador tape el contenido.

¿Cuál es la diferencia entre em y rem?

Las dos son relativas al tamaño de fuente. rem se calcula siempre sobre la fuente del elemento raíz, así que es constante en toda la web. em se calcula sobre la fuente del propio elemento, por lo que se acumula al anidar elementos. Para texto suele ir mejor rem.

¿Cuándo debo usar rem o px?

Usa rem para todo lo que deba escalar con la preferencia del usuario: tamaño de texto y espaciados. Reserva px para detalles que no deben cambiar de tamaño, como bordes de 1px, radios de esquina y sombras.

¿Por qué 100vh se pasa de largo en el móvil?

Porque vh se calcula sobre el viewport grande, sin contar la barra de direcciones del navegador. Cuando esa barra está visible, 100vh es más alto que el área real y el contenido se corta. La solución es 100dvh, que se ajusta al espacio disponible en cada momento.

¿Qué unidad uso para el tamaño de fuente?

rem como base, porque respeta el zoom y la accesibilidad. Si quieres que un título fluya con la pantalla, combínalo con vw dentro de clamp(), así fijas un mínimo y un máximo legibles.

¿vw y vh sirven para posicionar cualquier cosa?

No conviene abusar. Van bien para secciones a pantalla completa y para tipografía fluida con topes, pero para anchos dentro de un layout casi siempre es mejor % o min(), que respetan el contenedor y evitan scroll horizontal.

Con esta chuleta ya no tienes que dudar entre px, rem, em, vw o vh: cada una tiene su momento. Guárdate el artículo, y si te ha aclarado la eterna duda, compártelo con quien siga peleándose con el 100vh.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio