Usa rem para tamaños de fuente, espaciados y media queries. Usa px para lo que no debe cambiar de tamaño: un borde de un píxel, un ícono fijo, una línea divisoria fina. Usa em cuando un valor deba seguir el tamaño de fuente del elemento en el que vive, como el padding dentro de un botón. Las tres terminan siendo lo mismo, una longitud en píxeles CSS; la única diferencia es por qué número se multiplican y quién controla ese número.
| Unidad | Se multiplica por | Lo controla |
|---|---|---|
| px | Nada. 1px es 1px. | Tú, y nadie más. |
| rem | El tamaño de fuente calculado del elemento html. | La configuración del navegador del lector — salvo que la sobrescribas. |
| em | El tamaño de fuente calculado del propio elemento. En la propiedad font-size, el del padre. | El lugar donde el elemento caiga dentro de la cascada. |
¿Un píxel CSS es un píxel real?
No. CSS fija una pulgada en exactamente 96 px, lo que amarra cada unidad absoluta a todas las demás: 1pt es exactamente cuatro tercios de píxel y 1cm es 96 dividido entre 2,54, unos 37,8 px. Esas proporciones se cumplen en cualquier dispositivo. Lo que no describen es nada físico. Una pantalla con el doble de densidad de píxeles pinta cada píxel CSS con cuatro píxeles de hardware, y un teléfono aplica encima otra escala más para que el texto siga siendo legible a la distancia de un brazo. px es estable frente al resto de tu layout y no significa absolutamente nada frente al vidrio.
Por qué rem es la opción por defecto para el texto
Porque 16 px no es una constante, es un valor por defecto, y los valores por defecto se cambian. Chrome, Firefox y Edge ponen un control de tamaño de texto en su panel de ajustes normal, sin necesidad de entrar a ningún menú de accesibilidad. Ponlo en 20 y cada rem de la página crece una cuarta parte: 1rem deja de significar 16 px y pasa a significar 20. Todo lo que dimensionaste en px en esa misma página no se mueve.
Ese es todo el argumento, y vale la pena ser honesto sobre lo grande que es. La afirmación habitual de que el texto en px es inaccesible está exagerada. El propio documento Understanding del W3C para el criterio de éxito 1.4.4 —el que exige que el texto sobreviva a un cambio de tamaño del 200% sin romperse— da el contenido por aprobado si cualquier mecanismo de escalado de texto que ofrezca el navegador hace el trabajo, y el zoom de página completa escala px junto con todo lo demás. Bajo esa lectura, el texto de cuerpo en px no reprueba en esa casilla.
A quien sí le falla es al lector que nunca toca el zoom. El zoom también agranda imágenes, layout y longitudes de línea, y a mucha gente solo le interesa que las palabras sean más grandes. Configuran el tamaño de texto del navegador una vez, hace años, y después llegan a una página cuyo texto de cuerpo es font-size: 14px y no pasa nada. El interruptor «Aplicar zoom solo al texto» de Firefox es ese mismo grupo de personas pidiendo lo mismo. rem les responde, y a ti no te cuesta nada.
Cuándo px sigue siendo la respuesta correcta
Dimensionar todo en rem es un error real, solo que menos común. Usa px donde escalar haría que el valor fuera incorrecto y no simplemente distinto:
- Bordes y divisores. Un borde de 1 px escrito como
0.0625remse convierte en 1,25 px para un lector con una raíz de 20 px, y el navegador tiene que redondearlo: a veces a una línea visible, a veces a nada. Las líneas finas quieren un píxel fijo. - Medios de tamaño fijo. Un sprite de íconos o un logo dibujado a una resolución específica debe colocarse a esa resolución.
- Radios de desenfoque y desplazamientos pequeños en las sombras, donde un aumento proporcional se lee como falta de nitidez en lugar de como escala.
- Cualquier cosa alineada a un raster, como una imagen de fondo repetida con un paso en píxeles conocido.
Mezclar unidades dentro de una misma regla es normal, no es un code smell. padding: 1rem; border-bottom: 1px solid es exactamente lo correcto: el espacio sigue al texto, la línea no.
Para qué sirve em realmente
em se refiere al tamaño de fuente del propio elemento, con una excepción que causa casi toda la confusión. En la propiedad font-size, em se resuelve contra el tamaño de fuente del padre, porque el tamaño propio del elemento es justamente lo que se está calculando. En todo lo demás, padding incluido, se resuelve contra el tamaño ya calculado del propio elemento.
Esa excepción es la razón de que una lista anidada con estilo 0.9em se encoja en cada nivel: 0,9, luego 0,81, luego 0,729, y cuatro niveles más abajo una base de 16 px se ha convertido en unos 10,5 px. También es lo que hace que em sea genuinamente útil. Define un solo tamaño de fuente en un botón, expresa su padding, su gap y su border radius en em, y todo el componente escala como una unidad a partir de un único número. Cambia ese número y el botón crece correctamente sin tocar otras cuatro declaraciones.
La regla práctica: em cuando el valor le pertenece al componente, rem cuando le pertenece a la página. El padding de un botón es asunto del componente. El espacio entre dos secciones es asunto de la página.
En las media queries, em y rem son lo mismo
La especificación es explícita: las unidades relativas dentro de una media query se resuelven contra el tamaño de fuente inicial, nunca contra el resultado de una declaración. Así que @media (min-width: 40em) y @media (min-width: 40rem) producen un breakpoint idéntico, y a ninguno de los dos le afecta html { font-size: 62.5% }. Ambos siguen respetando el tamaño de texto por defecto del lector, que es justamente el punto: alguien que lee a 20 px llega al layout ancho más tarde, cuando su texto más grande de verdad necesita ese espacio. Un breakpoint en px ignora todo eso.
¿Entre cuánto hay que dividir para obtener rem?
Entre el tamaño de fuente de la raíz. Con el valor por defecto de 16 eso da 24 px = 1.5rem, 12 px = 0.75rem, 14 px = 0.875rem, 18 px = 1.125rem. Los redondos te los aprendes en una semana. Los raros los buscas toda la vida.
Hacer eso en una hoja de estilos entera es donde se va la tarde, así que vale la pena tener abierto un conversor de px a rem al lado del editor. Su botón «Leer de esta ventana» rellena el tamaño de fuente raíz que tu navegador calculó de verdad, que es la forma más rápida de descubrir que algo en tu propio CSS ya lo sobrescribió.
¿Vale la pena el truco del 62.5%?
html { font-size: 62.5% } hace que 1rem equivalga a 10 px para un lector con el valor por defecto, así que 1.6rem se lee directo en la página como «16px» y la división desaparece. La raíz sigue siendo un porcentaje de la configuración del lector, así que su preferencia sobrevive y esto no es un fallo de accesibilidad. La cuenta llega por la herencia. Ahora cada elemento sin estilos parte de 10 px, así que el body hay que reajustarlo de inmediato, y cualquier cosa que sueltes dentro y que esté escrita en rem —un date picker, una biblioteca de componentes, un widget incrustado— se renderiza un 37,5% más pequeña de lo que su autor pretendía. Bien en una base de código que controlas de punta a punta. Nada bien dentro del design system de otra persona.
Los cuatro errores que conviene conocer
Poner html { font-size: 16px }. Este es el que cancela en silencio todo lo anterior. Reemplaza la preferencia del lector por tu número, y ahora tu hoja de estilos cuidadosamente basada en rem se comporta exactamente como una basada en px. Si necesitas ajustar la raíz, usa un porcentaje o déjala en paz.
Ponerle una unidad a line-height. Un line-height: 1.5 sin unidad se hereda como proporción, así que cada hijo lo recalcula a partir de su propio tamaño de fuente. line-height: 1.5rem se hereda como una longitud fija, y un encabezado que lo herede recibe 24 px de caja de línea alrededor de un texto de 32 px. Sin unidad, siempre.
Usar em para el espaciado de la página. El margen entre dos secciones no debería cambiar porque una de ellas contenga texto más pequeño. Ese es un valor en rem.
Confiar en una conversión de em o % que no verificaste. px, rem, pt y las unidades físicas son aritmética exacta. em y % no lo son: su valor real depende del tamaño de fuente calculado de un elemento que tienes que ir a buscar, y ningún conversor puede leer tu cascada por ti. Escribe mal el tamaño del padre y te sale una respuesta segura de sí misma y equivocada.
Entonces, ¿qué deberías hacer?
Deja en paz el tamaño de fuente de la raíz. Escribe los tamaños de fuente, el espaciado vertical y los breakpoints en rem. Escribe los bordes, las líneas finas y los gráficos de tamaño fijo en px. Recurre a em dentro de un componente cuando quieras que un solo tamaño de fuente gobierne todo lo demás, y en ningún otro lugar. Mantén line-height sin unidad.
Con eso cubres casi todo. Las unidades que quedan son más estrechas: pt, cm y mm solo significan algo en una hoja de estilos para impresión; % significa algo distinto en casi cada propiedad en la que aparece; ch y ex dependen de las métricas del archivo de fuente concreto, que es la razón de que ningún conversor pueda calcularlas por ti. Y si una página está escrita en rem y aun así cuesta leerla, las unidades nunca fueron el problema: la relación de contraste que tu texto necesita es la otra mitad de la legibilidad, y es la mitad que la gente se salta.
La aritmética es trivial; hacerla cuarenta veces no lo es. Por eso conviene tener el conversor de unidades CSS abierto en una pestaña. Muestra un valor en once unidades a la vez, y cada fila dice cuál de tus cuatro suposiciones —tamaño de fuente de la raíz, tamaño de fuente del elemento, ancho del viewport, alto del viewport— produjo ese número. Las filas de em y % solo son tan confiables como el tamaño de fuente que escribiste, y ch y ex están ausentes a propósito, porque las métricas de los glifos no se pueden deducir con aritmética.
Si estás ordenando las unidades de una hoja de estilos, los valores de color suelen ser lo siguiente que aparece. HEX, RGB y HSL comparados hace la misma pregunta que este post —qué notación puedes editar a mano de verdad— pero sobre el color en lugar de la longitud.
Preguntas frecuentes
¿Debo usar px o rem en CSS?
Usa rem para todo lo que deba seguir el tamaño de texto del lector: tamaños de fuente, espaciado vertical y breakpoints. Usa px para todo lo que a un tamaño mayor quedaría incorrecto y no simplemente distinto, como un borde fino, un ícono de resolución fija o un desplazamiento pequeño de sombra. Los dos conviven a menudo en la misma regla: padding en rem con un borde de 1px debajo es lo correcto, no un code smell.
¿Cuál es la diferencia entre em y rem?
rem se mide contra el tamaño de fuente del elemento raíz html, así que un rem es la misma longitud en toda la página. em se mide contra el tamaño de fuente del elemento en el que aparece, salvo en la propia propiedad font-size, donde usa el del padre, porque el tamaño propio del elemento es justamente lo que se está calculando. Esa excepción es la razón de que em se acumule a través de elementos anidados y rem nunca lo haga.
¿Es malo usar px para el tamaño de fuente?
No incumple el criterio de éxito 1.4.4 de WCAG, que se satisface si funciona cualquier mecanismo de escalado de texto que ofrezca el navegador, y el zoom de página completa agranda el texto en px junto con el resto de la página. Lo que px ignora es al lector que subió el tamaño de texto por defecto del navegador en vez de usar el zoom; a esa persona tu página no le da nada. Como rem no cuesta nada extra, hay pocas razones para poner el texto de cuerpo en px.
¿html { font-size: 62.5% } causa problemas de accesibilidad?
Por sí solo no. La raíz sigue siendo un porcentaje del tamaño de texto que el lector haya elegido, así que su preferencia sigue escalando toda la página. El costo real es la herencia: ahora cada elemento parte de 10px en lugar de 16, así que el body necesita un reset explícito, y cualquier CSS de terceros escrito en rem se renderiza un 37,5% más pequeño de lo previsto.
¿Los breakpoints deben ir en px, em o rem?
em y rem se comportan igual dentro de una media query: la especificación de CSS dice que allí las unidades relativas se resuelven contra el tamaño de fuente inicial e ignoran cualquier font-size puesto en el elemento html. Cualquiera de las dos hace que los breakpoints sigan la preferencia de tamaño de texto del lector, así que quien lee con texto más grande llega al layout ancho cuando su texto de verdad necesita ese espacio. Un breakpoint en px ignora esa preferencia por completo.
¿Por qué mi lista anidada se hace cada vez más pequeña?
Porque un font-size en em se multiplica contra el tamaño de fuente del padre, así que se acumula una vez por cada nivel de anidamiento. Una regla de 0.9em es 0,81 del original dos niveles más abajo y 0,729 tres niveles más abajo; partiendo de 16px, eso son unos 11,7px. Escribe esa regla en rem, o acótala con un selector de hijo directo para que solo aplique al primer nivel.
Última actualización 19 de septiembre de 2026