1) Mobile-first con cabeza: breakpoints lógicos y centrados en el contenido
En mi día a día, “móvil primero” no es un eslogan: es lo que veo que convierte mejor y evita retrabajo. Yo arranco con una base limpia para pantallas pequeñas y voy añadiendo reglas cuando el diseño lo pide. Nada de tamaños mágicos “porque todo el mundo usa 768px”. Prefiero puntos de irrupción que aparecen cuando un bloque se rompe: si el titular salta a 3 líneas o si un grid se estrecha demasiado, ahí coloco la media query.
Cómo detecto breakpoints reales
- Abro el layout en devtools y estiro el viewport lentamente.
- Cuando un componente pierde legibilidad o aparece scroll horizontal, marco esa anchura y la redondeo solo lo justo.
- Validación en dispositivos físicos (siempre pruebo en un móvil de gama media y uno pequeño). Esa verificación me da una UX más fluida y, de paso, mejor rendimiento.
Orden recomendado
- Estilo base (mobile) al principio.
- Media queries al final del CSS, en bloque, por tema o por componente: me ha ahorrado choques de cascada y reglas duplicadas.
- Uso unidades relativas (em, rem, %) para que todo escale con tipografía y contenedores.
Cómo detectar “puntos de irrupción” reales con devtools y dispositivos físicos
- Reduce a lo esencial: tipografías con clamp(), una columna por defecto, imágenes a 100% del contenedor.
- Amplía el viewport poco a poco; cuando un componente se deforma, añade un breakpoint solo para ese patrón.
- Contrasta en hardware: girar a paisaje, cambiar densidad de píxeles, probar “modo con una mano”.
Orden y ubicación: por qué colocar @media al final del CSS te evita choques de cascada
- La cascada evalúa última regla que coincide. Si tus media queries están repartidas, es fácil pisarte.
- Un bloque final por componente/tema garantiza lectura lineal: base → ajustes en @media.
- Si trabajas con preprocesadores, genera una salida única con las @media agrupadas por ancho ascendente.
2) Media Queries que no fallan: sintaxis, media features y operadores
Las media queries filtran cuándo aplicar reglas según el contexto de presentación. En móvil primero, la pareja estrella es min-width y, para casos específicos, orientation, hover o pointer.
/* Base (mobile) */
.card { display: grid; gap: 1rem; }
/* Cuando el contenido lo pide */
@media (min-width: 42rem) {
.card { grid-template-columns: 1fr 1fr; }
}
/* Afinar interacción */
@media (hover: hover) and (pointer: fine) {
.menu a:hover { text-decoration: underline; }
}
/* Evitar mareos */
@media (prefers-reduced-motion: reduce) {
.hero { animation: none; transition: none; }
}
Media features que más uso
- min-width/max-width: diseño por viewport.
- orientation: retrato/paisaje (útil para héroes con imagen de fondo).
- hover y pointer: decide si tiene sentido mostrar estados hover complejos.
- prefers-reduced-motion y prefers-color-scheme: accesibilidad sin fricción.
Operadores
- and: encadena condiciones (ej.: tamaño + capacidad de hover).
- , (coma): OR lógico; útil para agrupar varios rangos.
- not: úsalo poco; es fácil crear huecos lógicos.
min-width vs max-width, orientation, hover, pointer
- Móvil primero → min-width: empiezas simple y “mejoras” cuando hay espacio.
- Ajustes puntuales → max-width: para recortes por debajo de cierto ancho.
- orientation: corrige solamente si el layout realmente cambia (no fuerces).
- hover/pointer: evita hover-dependencias en pantallas táctiles.
Combinaciones con and, , y not: patrones seguros
- “Mejora solo en pantallas anchas con puntero fino”:
@media (min-width: 64rem) and (pointer: fine) { /* ... */ }
- “Aplica a móvil o pantallas muy pequeñas”:
@media (max-width: 30rem), (max-height: 24rem) { /* ... */ }
- Evita not salvo para reset global en un caso extremo.
3) Unidades relativas que funcionan: em, rem y % para tipografías y layouts fluidos
Cambiar de px a unidades relativas me dio tipografías y espaciados que respiran mejor en cualquier anchura. Además, mejor compatibilidad con zoom del usuario y tamaños de fuente del sistema.
- rem: relativo a la raíz (típico html { font-size: 16px }). Ideal para escala tipográfica y ritmos verticales coherentes en toda la página.
- em: relativo al padre; perfecto para componentes que deben escalar con su contexto (botones dentro de cards, badges dentro de títulos).
- %: relativo a dimensiones del contenedor (ancho/alto), útil para imágenes fluidas y columnas.
Escalas tipográficas con clamp()
:root { --step: 1.125; } /* escala mayor */
h1 { font-size: clamp(1.75rem, 2.5vw + 1rem, 3rem); }
p { font-size: clamp(1rem, 1.2vw + .75rem, 1.125rem); }
Con clamp() fijo un mínimo, un crecimiento fluido y un máximo sin romper líneas.
Grillas fluidas con minmax() y auto-fit/auto-fill
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: 1rem;
}
Así el grid se autoencaja sin forzar breakpoints rígidos.
4) Más allá de @media: cuándo usar container queries
Las container queries (@container) miran el tamaño del contenedor, no el viewport. Brillan en componentes reutilizables: cards, sidebars, product tiles. Si ese componente vive en un layout estrecho, se adapta sin necesitar un breakpoint global.
/* Define contenedor con tamaño “medible” */
.card-list { container-type: inline-size; }
/* Cambia el patrón de la card según su contenedor */
@container (min-width: 36rem) {
.card { display: grid; grid-template-columns: 1fr 2fr; }
}
@container para componentes reutilizables
- Un mismo componente puede verse en 1, 2 o 3 columnas dependiendo solo del ancho de su padre.
- Reduce media queries globales y evita que un pequeño cambio de layout rompa vistas lejanas.
Migraciones progresivas desde media queries por viewport
- Mantén media queries para estructura general (header, grid principal).
- Pasa a @container los widgets con vida propia (cards, menús, promos).
- Evita duplicar reglas: si un ajuste depende del componente, va en @container.
5) Rendimiento y UX: pruebas en dispositivos reales que mueven la aguja
Mi checklist rápido antes de publicar:
- Dispositivos reales: al menos un gama media Android y un iPhone pequeño. Giro a paisaje, pruebo teclado en pantalla, verifico zoom.
- Redes lentas: emulo 3G/4G con throttling; imágenes con srcset/sizes.
- Accesibilidad: contrastes, foco visible, prefers-reduced-motion.
- Web Vitals: LCP sin héroes pesados, CLS con dimensiones reservadas, INP con interacciones simples.
Imágenes, fuentes y JavaScript: lo mínimo para no romper el LCP
- Imágenes: formatos modernos + width/height + lazy donde no sea above-the-fold.
- Fuentes: font-display: swap y pocas variantes.
- JS: diferido y crítico mínimo; no encadenes listeners que dependan de tamaño si CSS ya lo resuelve.
6) Casos prácticos rápidos
Navbar que cambia de patrón (hamburger ↔ inline)
- Base: botón menú simple.
- A partir de que el texto no colisione, @media (min-width: …) muestro la navegación en línea.
Cards responsivas con texto largo y botones
- Base: una columna; botones a 100%.
- Con @container (min-width: …) paso a 2 columnas y limito el título con line-clamp para evitar saltos.
Hero que no “salta” al rotar el dispositivo
- Reservo altura del media con aspect-ratio.
- Ajusto tipografías con clamp(); si orientation: landscape, reduzco padding vertical.
FAQ: dudas comunes sobre media queries bien aplicadas
¿Cuáles son los breakpoints “recomendados”?
Los que tu contenido pida. Empieza sin ninguno, añade cuando un bloque se rompa. Si necesitas guías: ~36rem, ~48rem, ~64rem, ~80rem.
¿Mobile-first o desktop-first?
Mobile-first con min-width me ha dado CSS más corto y menos colisiones. Desktop-first tiene sentido si migras un legacy.
¿Dónde ubicar las media queries en el CSS?
Al final del archivo/hoja, agrupadas por tema o componente. Menos sorpresas de cascada.
¿Cuándo usar container queries en vez de media queries?
Si el ajuste depende del ancho del componente, no del viewport, usa @container.
¿Qué unidades elegir: px, em, rem, %?
Tipografías y espaciados globales en rem, componentes en em, anchos relativos en %.
Guías de decisión (sin tablas)
A) Media queries por viewport vs container queries
- Si el cambio afecta al layout global (header, grid principal, sidebar del layout), usa media queries con min-width.
- Si el cambio depende del ancho del componente (una card que se muestra en 1 o 2 columnas según el espacio dentro de una sección), usa @container.
- Si necesitas ambas cosas (estructura global + detalles del widget), combina: viewport para el esqueleto, container para el comportamiento interno.
- Si el componente aparece en layouts muy distintos (homepage, detalle, sidebar), prioriza @container para no sembrar breakpoints globales innecesarios.
- Si solo quieres ocultar/mostrar decoraciones según capacidades de entrada, considera media features como (hover) o (pointer) antes de meter @container.
Regla mental rápida
- ¿El criterio es “¿cuánto mide la página?” → Viewport (@media).
- ¿El criterio es “¿cuánto espacio tiene este bloque?” → Componente (@container).
B) em vs rem (y %) con reglas claras
- Texto base y escala global → rem (coherencia y respeto al zoom del usuario).
- Componentes que deben escalar con su contexto (botones dentro de títulos, badges) → em.
- Espacios internos de componentes (padding/margin) → em si quieres que crezcan con la tipografía del componente; rem si quieres ritmo global fijo.
- Anchos flexibles de elementos fluidos → % (respecto al contenedor).
- Evita px salvo casos de pixel-fit (bordes 1px, detalles de iconos).
Regla mental rápida
- “¿Debe escalar con toda la página?” → rem.
- “¿Debe escalar con este componente?” → em.
- “¿Debe ocupar parte del contenedor?” → %.
Conclusión
Un responsive sólido no va de copiar breakpoints, sino de escuchar al contenido. Arranco con mobile-first, coloco @media solo donde el layout lo pida, trabajo con unidades relativas y pruebo en dispositivos reales. Cuando un componente debe decidir por sí mismo, saco la carta de @container. Este enfoque me ha dado mejores experiencias y, sobre todo, páginas que convierten.