PX vs REM vs EM: la guía completa de unidades CSS
Aquí está la respuesta corta a px vs rem vs em, antes de cualquier explicación. Usa rem para casi todo el dimensionamiento (tamaños de fuente, padding, márgenes, gaps, border-radius y breakpoints) porque escala con la configuración de tamaño de fuente del navegador del lector. Usa px para las pocas cosas que nunca deberían escalar, como un borde de 1px o el desplazamiento preciso de una sombra. Usa em para el caso local poco frecuente en el que un valor debe crecer junto con el tamaño de fuente del propio elemento, como el padding de un botón que acompaña a su texto.
Esa regla cubre el 90% de las decisiones. El otro 10% es donde están los problemas: la matemática del em compuesto que sorprende a todos la primera vez, el bug de media query que rompe los diseños al hacer zoom, y los casos en los que px es en realidad la opción más accesible. Esta guía recorre los tres, con CSS ejecutable para cada uno, además de una chuleta por propiedad que puedes mantener abierta mientras escribes estilos.
Qué significan realmente px, rem y em
Tres unidades, tres puntos de referencia distintos. Esa es toda la distinción.
px es una unidad absoluta. Un px es un píxel CSS, y conserva ese tamaño sin importar lo que lo rodee. border: 1px solid es un píxel, punto. La trampa es que “absoluto” también significa que ignora las preferencias del usuario; más adelante veremos por qué eso importa.
rem es relativo al tamaño de fuente del elemento raíz. La raíz es <html>, y los navegadores establecen su tamaño de fuente en 16px por defecto. Así que 1rem equivale a 16px en una configuración estándar, en toda la página, sin importar el anidamiento. Esa consistencia es lo que lo hace útil: hay un único valor ancla y el resultado no depende del contexto.
em es relativo al tamaño de fuente del elemento actual (o de su padre, en las propiedades que no son font-size). Como esa referencia cambia a medida que anidas elementos, los valores en em se desplazan según el contexto. El mismo 1.5em puede resolverse a 24px en un lugar y a 30px en otro.
El ancla que hay que memorizar es 16px = 1rem. Si no interiorizas nada más, interioriza eso. Cuando necesites traducir un valor específico, el conversor de px a rem hace la división contra la base que elijas.
px vs rem vs em de un vistazo
| Unidad | Relativa a | ¿Escala con el tamaño de fuente del usuario? | Uso típico | Comportamiento al anidar |
|---|---|---|---|---|
px | Nada (absoluta) | No | Bordes, desplazamientos de sombra, líneas finas | Siempre el mismo tamaño |
rem | Tamaño de fuente de la raíz <html> | Sí | Tamaño de fuente, espaciado, breakpoints | Siempre el mismo tamaño |
em | Tamaño de fuente del elemento actual | Sí | Valores locales ligados a un componente | Se compone: puede desviarse |
Las dos columnas que deciden la mayoría de las discusiones son “escala con el tamaño de fuente del usuario” y “comportamiento al anidar”. rem gana en ambas: respeta la preferencia del lector y se mantiene predecible. em comparte el primer beneficio pero renuncia al segundo.
Cómo se calcula cada unidad
La matemática es aritmética simple. Lo que confunde a la gente es por qué número dividir o multiplicar.
rem usa el tamaño de fuente de la raíz:
rem = px ÷ root-font-size
Con la raíz por defecto de 16px, 24px ÷ 16 = 1.5rem. Para volver atrás, multiplica: 1.5rem × 16 = 24px. Cada rem de la página usa ese mismo 16 (o el valor que hayas asignado a la raíz), que es exactamente por lo que rem es predecible.
em usa el tamaño de fuente del propio elemento actual:
em = px ÷ current-element-font-size
Si el font-size de un elemento es 20px, entonces 1em en ese elemento es 20px, 0.5em es 10px, y un padding de 1.5em es 30px. Cambia el tamaño de fuente del elemento y todos los valores em ligados a él cambian con él. Ese acoplamiento local es el sentido del em, y también su trampa.
La trampa del em compuesto
Esta es la parte que los competidores pasan por alto. Cuando anidas elementos que usan todos em para el tamaño de fuente, los valores se multiplican hacia abajo en el árbol. Cada nivel hereda el tamaño de fuente calculado de su padre y le aplica encima su propio factor em.
.menu { font-size: 1.2em; } /* el padre es 16px → 19.2px */
.menu .item { font-size: 1.2em; } /* el padre es 19.2px → 23.04px */
.menu .item .sub { font-size: 1.2em; } /* el padre es 23.04px → 27.648px */
Cada nivel es “el 120% de su padre”, lo que suena inofensivo. Pero como el padre ya creció, el tercer nivel es 1.2 × 1.2 × 1.2 = 1.728em respecto al 16px original, unos 27.6px, no los 19.2px que podrías haber leído de la regla de forma aislada. Anida una lista dentro de una lista dentro de un componente y el texto se infla de una forma difícil de rastrear.
rem esquiva esto por completo. 1.2rem es 19.2px tanto si está al inicio del documento como doce niveles más abajo, porque siempre se mide contra la raíz, nunca contra el padre. Cuando un valor se resuelve a un tamaño que no esperabas, la primera pregunta que debes hacerte es si es em (relativo al padre, se compone) o rem (relativo a la raíz, estable). Si estás depurando un rem perdido y quieres ver su tamaño en píxeles rápido, el conversor de rem a px lo resuelve al instante.
Cuándo usar rem
Recurre a rem por defecto. Es la unidad correcta para los tamaños de fuente, el padding, los márgenes, los gaps, el border-radius y los breakpoints de las media queries: cualquier cosa que deba escalar cuando un lector ajusta el tamaño de su texto.
Esa última cláusula es el argumento de accesibilidad, y no es hipotético. Las encuestas de WebAIM a usuarios de lectores de pantalla y con baja visión encuentran de forma consistente que una buena parte de los usuarios ajusta el tamaño de fuente por defecto de su navegador o sistema operativo, muchos de ellos bastante por encima del estándar de 16px. Un diseño dimensionado en rem respeta ese cambio: sube el valor por defecto a 20px y cada valor basado en rem crece proporcionalmente. Un diseño dimensionado en px lo ignora por completo: el texto se queda fijo en su tamaño codificado, sin importar cuánto lo necesite más grande el lector.
:root {
font-size: 16px; /* 1rem = 16px */
}
h1 { font-size: 2rem; } /* 32px, escala con la preferencia del usuario */
p { font-size: 1rem; } /* 16px */
.card { padding: 1.5rem; } /* 24px */
.card { border-radius: 0.5rem; } /* 8px */
Como aquí cada valor está anclado a la misma raíz, un único cambio en el tamaño de fuente de la raíz reescala toda la interfaz de forma proporcional. Eso es también lo que mantiene coherente un sistema de diseño: el espaciado y la tipografía se mueven juntos en lugar de separarse.
El truco del 62.5%
Hay un atajo popular para hacer trivial la aritmética de rem. Establece el tamaño de fuente de la raíz en 62.5%, que es 62.5% × 16px = 10px:
html {
font-size: 62.5%; /* ahora 1rem = 10px */
}
body {
font-size: 1.6rem; /* restaura el texto del cuerpo legible a 16px */
}
h1 { font-size: 2.4rem; } /* 24px */
p { font-size: 1.6rem; } /* 16px */
Con una raíz de 10px, el cálculo mental se reduce a “divide el valor en píxeles entre 10”: 24px → 2.4rem, 12px → 1.2rem. La única arruga es restaurar un tamaño de cuerpo legible con body { font-size: 1.6rem }, ya que una base cruda de 10px deja el texto por defecto demasiado pequeño. Usar 62.5% como porcentaje en lugar de 10px lo mantiene relativo, de modo que un lector que escale el valor por defecto de su navegador sigue obteniendo un crecimiento proporcional. Si adoptas esta base, ajusta el tamaño de fuente de la raíz del conversor a 10 para que coincida con tu hoja de estilos.
Cuándo usar em
Usa em cuando quieras que un valor escale con el tamaño de fuente propio del elemento, no con el de la raíz. El caso clásico es un botón:
.btn {
font-size: 1rem; /* dimensionado contra la raíz */
padding: 0.75em 1.5em; /* el padding acompaña al texto del botón */
}
.btn--large {
font-size: 1.25rem; /* un cambio redimensiona todo */
}
Como el padding está en em, el modificador .btn--large redimensiona el texto y su padding juntos desde una sola declaración: el botón se mantiene proporcional en cualquier tamaño. La misma lógica aplica a un icono dimensionado en em para que coincida con la línea de texto en la que está, o a un letter-spacing que deba crecer con la fuente.
La estrategia que funciona en la práctica es rem para el esqueleto global y em para las proporciones locales. Establece el tamaño de fuente en rem para que responda a la raíz y a la preferencia del usuario; establece en em el puñado de valores que deben acompañar a ese elemento. Solo mantén el em fuera de cualquier cosa que se anide profundamente, o la trampa del em compuesto de antes vuelve a colarse.
Cuándo usar px
Algunos valores genuinamente no deberían escalar, y px es lo correcto para ellos: un borde fino de 1px, un desplazamiento preciso de box-shadow, un anillo de foco de 2px. Son detalles de renderizado, no contenido. Un borde que “escala” a 1.25px cuando el usuario agranda su texto no gana nada y puede renderizarse como una línea borrosa. px lo mantiene nítido.
.divider { border-bottom: 1px solid; } /* debe quedarse en 1px */
.card { box-shadow: 0 2px 4px rgba(0,0,0,0.1); } /* desplazamiento fijo */
.input:focus { outline: 2px solid; } /* anillo de foco nítido */
El matiz sorprendente: cuándo px es más accesible
La parte contraintuitiva, que la mayoría de los consejos de “usa rem siempre” se saltan, es que la opción accesible no es “rem en todas partes”. Es “escala lo que debe escalar, fija lo que no”.
Un borde de 1px es un detalle fijo. Forzarlo a rem para que crezca cuando el usuario agranda el texto no ayuda a la legibilidad: solo hace que una línea fina se vea borrosa. Para estas propiedades, px es la opción más accesible precisamente porque se queda quieto.
El error que la gente comete en realidad es el contrario: usar px para las cosas que deberían responder, como los tamaños de fuente y los breakpoints. Ahí es donde px daña la accesibilidad. Así que la regla no es sobre la unidad, es sobre la propiedad. Pregúntate si el valor es contenido con el que el lector interactúa (escálalo: rem) o un detalle de renderizado fijo (fíjalo: px). La unidad se deduce de la respuesta.
La trampa de las media queries
Esta rompe diseños reales y casi ninguna guía la advierte. Los breakpoints de media query escritos en px no responden al zoom de tamaño de fuente del navegador como esperarías.
Imagina un breakpoint en width: 600px donde una barra lateral se colapsa. Un usuario con visión reducida ajusta el valor por defecto de su navegador a 24px para leer cómodamente. Tu contenido ahora necesita más espacio horizontal: el texto más grande quiere reorganizarse antes. Pero un breakpoint en px no sabe que el texto creció; sigue cambiando exactamente a los 600px de viewport, así que el diseño cambia en el momento equivocado y el contenido se aprieta o se solapa.
Compara los dos enfoques:
/* breakpoint en px: ignora la preferencia de tamaño de fuente del usuario */
@media (min-width: 600px) {
.sidebar { display: block; }
}
/* breakpoint en em/rem: responde al tamaño de fuente del usuario */
@media (min-width: 37.5em) {
.sidebar { display: block; }
}
37.5em es 600px con los 16px por defecto (600 ÷ 16 = 37.5). La diferencia es de comportamiento: cuando el usuario duplica su tamaño de fuente por defecto, el breakpoint en em también se duplica efectivamente, así que el diseño cambia a un ancho de viewport proporcional al texto, justo cuando el contenido lo necesita. El breakpoint en px se queda congelado.
Una particularidad que conviene saber: en las condiciones de media query, em y rem se resuelven ambos contra el tamaño de fuente por defecto del navegador, no contra ningún override de html, así que se comportan de forma idéntica allí. Cualquiera de las dos unidades corrige el bug; px lo provoca.
La tabla de decisión por propiedad
Cuando tengas dudas, esta tabla las responde. Es la forma más rápida de tomar la decisión sin volver a deducir la lógica cada vez.
| Propiedad | Unidad recomendada | Por qué |
|---|---|---|
font-size | rem | Escala con la preferencia de tamaño de fuente del usuario |
padding / margin | rem | El espaciado escala junto con el texto |
border | px | Las líneas finas deben quedarse nítidas y fijas |
desplazamiento de box-shadow | px | Un detalle de renderizado preciso, no contenido |
border-radius | rem | Mantiene la redondez de las esquinas proporcional a la escala |
| media query | em / rem | Los breakpoints deben responder al zoom de tamaño de fuente |
width / max-width | rem (a menudo ch para texto) | Anchos de diseño escalables; ch limita la longitud de línea |
line-height | sin unidad | Un multiplicador sin unidad se hereda correctamente |
La fila de line-height merece una nota porque es un bug común. Escribe siempre line-height: 1.5, sin unidad. Un valor sin unidad es un multiplicador que cada elemento calcula contra su propio tamaño de fuente, así que los elementos anidados se mantienen legibles. Escribe line-height: 1.5em o 24px en su lugar y se hereda la longitud calculada, lo que significa que un hijo con un tamaño de fuente mayor conserva el line-height del padre y su texto empieza a chocar. Sin unidad evita todo el problema.
Convertir entre px y rem
La aritmética es lo bastante pequeña como para hacerla mentalmente una vez que tienes el ancla: 16px = 1rem. Divide entre 16 para pasar a rem, multiplica por 16 para volver a px.
| px | rem (base 16px) |
|---|---|
| 8px | 0.5rem |
| 12px | 0.75rem |
| 16px | 1rem |
| 24px | 1.5rem |
| 32px | 2rem |
Si usas el truco del 62.5%, la base pasa a ser 10px y la matemática es aún más simple: solo divide o multiplica por 10, así que 24px = 2.4rem. La única regla es convertir siempre contra la base que tu hoja de estilos establece de verdad.
Para todo lo demás (valores raros, una raíz personalizada o convertir por lotes una exportación de Figma) sáltate el cálculo mental y usa el conversor de px a rem o el conversor de rem a px. Ambos te permiten establecer cualquier tamaño de fuente de la raíz y convertir en cualquier dirección en tiempo real. Y si después estás ordenando una hoja de estilos llena de unidades mezcladas, el formateador CSS te normalizará el espaciado y la indentación.
Errores comunes
Unos pocos patrones causan la mayor parte de los problemas relacionados con las unidades:
Establecer el tamaño de fuente de la raíz en px. Escribir html { font-size: 16px } (en lugar de dejar el valor por defecto o usar 100% / un porcentaje) anula directamente la preferencia de tamaño de fuente del navegador del usuario. Los valores rem siguen calculándose contra él, pero el lector ya no puede escalar toda la página. Deja la raíz con el valor por defecto, o usa un porcentaje.
Mezclar px y rem sin sistema. Algunos tamaños de fuente en px, otros en rem, el espaciado repartido entre ambos: el resultado es un diseño que escala de forma desigual cuando un usuario ajusta su texto. Elige rem como unidad por defecto y reserva px para las excepciones deliberadas de la tabla de decisión.
Usar em para el espaciado global. El em en contenedores ampliamente anidados reintroduce la trampa del em compuesto, así que un padding en lo profundo del árbol se resuelve a algo que nadie pretendía. Mantén el espaciado global en rem; reserva el em para valores locales, acotados a un componente.
Darle una unidad al line-height. Como vimos arriba, line-height: 24px o 1.5em se hereda como una longitud calculada y se rompe en elementos con distintos tamaños de fuente. Usa siempre un multiplicador sin unidad.
Preguntas frecuentes
¿Es rem mejor que px?
Para la mayoría del dimensionamiento, sí: rem es mejor que px porque escala con la preferencia de tamaño de fuente del navegador del usuario, que px ignora. Pero “mejor” depende de la propiedad: px es la opción correcta para detalles fijos como los bordes de 1px y los desplazamientos de sombra que deben quedarse nítidos. Usa rem para dimensionar contenido, px para detalles de renderizado.
¿Cuánto es 1rem en píxeles?
1rem equivale al tamaño de fuente de la raíz en píxeles, que es 16px por defecto en prácticamente todos los navegadores. Así que 1rem = 16px, 1.5rem = 24px y 2rem = 32px en una configuración estándar. Si una hoja de estilos sobrescribe html { font-size }, por ejemplo a 10px mediante el truco del 62.5%, entonces 1rem equivale a ese valor en su lugar.
¿Debo usar rem o em para font-size?
Usa rem para font-size en casi todos los casos. Rem se mide contra la raíz, así que se mantiene predecible sin importar cuán profundamente esté anidado un elemento. Em se mide contra el tamaño de fuente del padre, que se compone hacia abajo en el árbol y hace que el texto anidado se infle de forma inesperada. Reserva em para valores locales ligados a un solo componente.
¿Cuándo debo usar px en lugar de rem?
Usa px para valores que no deben escalar con el tamaño de fuente del usuario: bordes de 1px, desplazamientos precisos de box-shadow, contornos de anillos de foco y otros detalles de renderizado fijos. Son detalles de diseño nítidos más que contenido, así que fijarlos en px es la opción más accesible. Todo lo relacionado con el contenido debería seguir usando rem.
¿Por qué se rompen las media queries cuando uso px?
Los breakpoints de media query en px no responden al zoom de tamaño de fuente del navegador. Cuando un usuario agranda su fuente por defecto, su contenido necesita más espacio, pero un breakpoint en px sigue cambiando al mismo ancho de viewport, así que el diseño cambia en el momento equivocado. Usa breakpoints en em o rem, que escalan con el tamaño de fuente del usuario.
¿Qué es el truco del tamaño de fuente del 62.5%?
El truco del 62.5% establece html { font-size: 62.5% }, haciendo que el tamaño de fuente de la raíz sea 10px (el 62.5% de 16). Con una base de 10px, la matemática de rem se convierte en “divide entre 10”: 24px = 2.4rem, 12px = 1.2rem. Los desarrolladores luego establecen body { font-size: 1.6rem } para restaurar un texto del cuerpo legible de 16px.
¿Está bien mezclar px, rem y em?
Sí, mezclar px, rem y em es correcto cuando cada uno sigue la propiedad que le conviene: rem para tipografía y espaciado, px para detalles fijos, em para valores locales acotados a un componente. Lo que causa problemas es mezclarlos sin sistema: algunos tamaños de fuente en px y otros en rem, por ejemplo. Elige rem como unidad por defecto y trata px y em como excepciones deliberadas.
¿Qué unidad debo usar para padding y margin?
Usa rem para padding y margin para que el espaciado escale junto con el texto cuando el usuario ajusta su tamaño de fuente. Esto mantiene un diseño proporcional y accesible. Reserva em para el padding que deba acompañar al tamaño de fuente propio de un elemento, como un botón cuyo padding crece con su texto, y evita el em en contenedores profundamente anidados donde se compone.