Saltar al contenido

CSS, de a poco

Curso de CSS

Media queries

Lección 20 de 37 · 3 min

Una media query aplica estilos solo cuando se cumple una condición: que la pantalla tenga cierto ancho, que quien lee use tema oscuro o que prefiera menos movimiento.

Qué es una media query

Una media query (@media) envuelve reglas que solo valen si su condición es verdadera. La más común pregunta por el ancho del viewport, el área visible de la página.

Lo recomendado es mobile-first: escribí primero los estilos para pantallas chicas, sin ninguna media query, y sumá cambios a medida que hay más lugar. Cada media query pide un ancho mínimo, con min-width o con la sintaxis de rango (width >= 640px). Las dos dicen lo mismo, 640px incluido, pero la de rango se lee mejor y funciona en todos los navegadores actuales.

tarjetas.css
.tarjetas {
display: grid;
gap: 16px;
}
@media (min-width: 640px) {
.tarjetas { grid-template-columns: repeat(2, 1fr); }
}
/* lo mismo, con sintaxis de rango */
@media (width >= 640px) {
.tarjetas { grid-template-columns: repeat(2, 1fr); }
}

Mové el ancho del viewport y mirá cuándo la grilla pasa de 1 a 2 y a 3 columnas. Desde 1024px se cumplen las dos media queries, y gana la última porque viene después en el archivo.

width: 720px(width >= 640px) · 2 columnas
tema
pagina.css
.pagina {
background: #fff;
color: #111;
}
.programa {
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 16px;
}
@media (width >= 640px) {
.programa {
grid-template-columns: repeat(2, 1fr);
}
}
@media (width >= 1024px) {
.programa {
grid-template-columns: repeat(3, 1fr);
}
}
@media (prefers-color-scheme: dark) {
.pagina {
background: #111;
color: #eee;
}
}
@media (prefers-reduced-motion: no-preference) {
.indicador {
animation: girar 1s linear infinite;
}
}
@keyframes girar {
to {
rotate: 360deg;
}
}
pagina.html
<body class="bg-white text-neutral-900 dark:bg-neutral-950 dark:text-neutral-100">
<span class="size-4 rounded-full border-2 border-current border-t-transparent motion-safe:animate-spin"></span>
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
<section>Viernes 14</section>
<section>Sábado 15</section>
<section>Domingo 16</section>
</div>
</body>

Preferencias de quien lee

Las media queries también leen ajustes del sistema o del navegador. Las más útiles:

  1. Temaprefers-color-schemelight o dark, según el tema del sistema. Este sitio la usa: cambiá el tema de tu sistema y la página pasa de claro a oscuro.
  2. Movimientoprefers-reduced-motionVale reduce cuando la persona pidió menos movimiento, y no-preference si no pidió nada.
  3. Contrasteprefers-contrastmore o less cuando pidió más o menos contraste.
  4. Punterohover · pointerQué puede hacer el dispositivo de entrada principal: (hover: hover) si puede pasar el cursor por encima, y (pointer: coarse) si apunta con poca precisión, como un dedo.
preferencias.css
@media (prefers-color-scheme: dark) {
.pagina { background: #111; color: #eee; }
}
@media (prefers-reduced-motion: no-preference) {
.indicador { animation: girar 1s linear infinite; }
}
@media (pointer: coarse) {
button { min-height: 44px; }
}

Poné la animación adentro de no-preference en vez de sacarla con reduce: si un navegador no conoce la consulta, la condición da falso y no anima.

Cómo elegir los breakpoints

Un breakpoint es el ancho donde cambia el diseño. No hay una lista correcta de tamaños de dispositivos, y cambia cada año. Achicá la ventana hasta que algo se rompa (líneas muy largas, columnas apretadas) y poné el breakpoint ahí: decide el contenido, no el modelo de teléfono.

Dentro de una media query, em y rem no dependen del CSS de la página: se calculan con el tamaño de letra inicial del navegador, 16px por defecto. Con (width >= 40em), si alguien sube ese tamaño a 20px, el breakpoint pasa de 640px a 800px y el diseño cambia cuando el texto más grande ya no entra. Con el zoom no hay diferencia: el viewport medido en px también se achica, así que los breakpoints en px reaccionan igual.

El mismo breakpoint de 40em con dos tamaños de letra. Con 16px, por defecto, cae en 640px; si quien lee sube la letra a 20px, pasa a 800px y la segunda columna aparece más tarde.

Una media query mira la ventana entera. Si un componente puede ir en una barra lateral angosta o en el área principal, lo que importa es el lugar que le dan: para eso están las container queries, el tema de la próxima lección.

En Tailwind

En Tailwind cada media query es una variante: un prefijo delante de la clase. Las de ancho son mobile-first, igual que el demo: sm: aplica desde 40rem (640px) y lg: desde 64rem (1024px).

CSSTailwind
(width >= 640px) · 768px · 1024pxsm: · md: · lg:
(width < 640px)max-sm:
(width >= 900px)min-[900px]:
prefers-color-scheme: darkdark:
prefers-reduced-motion: no-preference · reducemotion-safe: · motion-reduce:
prefers-contrast: more · pointer: coarsecontrast-more: · pointer-coarse:
pagina.html
<body class="bg-white dark:bg-neutral-950 dark:text-neutral-100">
<span class="size-4 rounded-full border-2 motion-safe:animate-spin"></span>
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
<article>…</article>
</div>
<button class="hover:bg-neutral-100 pointer-coarse:min-h-11">Enviar</button>
</body>