Tema
Responsive design
Más del 60 % de las visitas a un sitio llegan desde un celular. Un sitio que no se adapta pierde clientes y posiciones en Google. En esta lección aprenderás el enfoque mobile-first, las media queries (incluidas las de preferencias del usuario), los breakpoints más usados y las técnicas de imágenes y tipografía fluidas para que tus sitios se vean perfectos en cualquier pantalla.
Concepto
Responsive design significa que un mismo sitio se adapta al tamaño y las capacidades del dispositivo, sin versiones separadas para móvil y escritorio. Se basa en tres pilares:
- Layouts fluidos: medidas relativas (
%,fr,flex) en lugar de anchos fijos. - Medios flexibles: imágenes y videos que nunca se desbordan.
- Media queries: reglas CSS que se aplican sólo bajo ciertas condiciones.
Analogía
El agua toma la forma del recipiente que la contiene. Un sitio responsive es como el agua: el mismo contenido se acomoda a una taza (móvil), a un vaso (tablet) o a una jarra (escritorio).
Paso 1: la meta viewport
Sin esta línea en el head, los móviles muestran la página como si fuera de escritorio (980px de ancho) y la reducen. Es obligatoria:
html
<meta name="viewport" content="width=device-width, initial-scale=1.0">Media queries
css
/* Se aplica sólo si la ventana mide 768px o más */
@media (min-width: 768px) {
.menu { display: flex; }
}
/* Sólo si mide 767px o menos */
@media (max-width: 767px) {
.menu { display: none; }
}
/* Sintaxis de rango moderna (todos los navegadores actuales) */
@media (width >= 768px) { }
@media (600px <= width < 1024px) { }
/* Combinar condiciones */
@media (min-width: 768px) and (orientation: landscape) { }
/* Sólo pantalla o sólo impresión */
@media print {
.header, .footer, .boton { display: none; }
body { color: #000; background: #fff; }
}Mobile-first: el enfoque profesional
Mobile-first significa escribir primero los estilos para móvil (sin media query) y luego añadir cambios para pantallas más grandes con min-width.
css
/* ===== Base: móvil ===== */
.servicios {
display: grid;
gap: 1rem; /* una columna */
}
/* ===== Tablet ===== */
@media (min-width: 640px) {
.servicios {
grid-template-columns: repeat(2, 1fr);
}
}
/* ===== Escritorio ===== */
@media (min-width: 1024px) {
.servicios {
grid-template-columns: repeat(4, 1fr);
}
}¿Por qué es mejor?
- El móvil suele tener el diseño más simple (una columna); es más fácil añadir complejidad que quitarla.
- Los móviles, que suelen tener peor conexión y CPU, procesan menos CSS.
- Te obliga a priorizar el contenido importante.
- Google indexa la versión móvil de tu sitio (mobile-first indexing).
Error común
Diseñar todo para escritorio y luego "arreglar" el móvil con decenas de max-width que sobrescriben estilos. El CSS crece, se vuelve frágil y siempre aparece algún elemento roto en pantallas pequeñas.
Breakpoints comunes
No hay valores "oficiales"; los breakpoints deben ponerse donde tu diseño se rompe, no según dispositivos concretos. Como referencia, estos son los de Tailwind CSS, muy usados:
| Nombre | min-width | Dispositivos típicos |
|---|---|---|
| (base) | 0 | Móviles |
sm | 640px | Móviles grandes horizontal |
md | 768px | Tablets |
lg | 1024px | Laptops, tablets horizontal |
xl | 1280px | Escritorio |
2xl | 1536px | Pantallas grandes |
Buena práctica
Usa pocos breakpoints (2–3 suelen bastar) y define todos los de un componente juntos, justo debajo de sus estilos base. Así sabes dónde mirar cuando el cliente pida un cambio.
Mira el enfoque en acción
Usa los botones de móvil, tablet y escritorio de la demo y observa el indicador de la esquina:
Imágenes fluidas
css
img,
video {
max-width: 100%; /* nunca más anchas que su contenedor */
height: auto; /* conserva la proporción */
display: block;
}Para servir imágenes de distinto tamaño según la pantalla (y ahorrar datos en móvil), usa srcset y sizes en HTML:
html
<img
src="img/hero-800.webp"
srcset="img/hero-400.webp 400w, img/hero-800.webp 800w, img/hero-1600.webp 1600w"
sizes="(min-width: 1024px) 50vw, 100vw"
alt="Interior de la cafetería con luz natural"
width="1600" height="900">Y para recortes distintos (dirección de arte), picture:
html
<picture>
<source media="(min-width: 768px)" srcset="img/banner-horizontal.webp">
<img src="img/banner-vertical.webp" alt="Promoción de temporada">
</picture>Lo ves a fondo en la lección de imágenes del curso de HTML.
object-fit
Cuando una imagen debe llenar una caja de proporción fija sin deformarse:
css
.tarjeta__imagen {
width: 100%;
aspect-ratio: 4 / 3;
object-fit: cover; /* recorta para llenar */
object-position: center top; /* qué parte se conserva */
}Tipografía y espaciado fluidos
Con clamp() el texto crece de forma continua entre un mínimo y un máximo, sin saltos ni media queries:
css
h1 {
/* mínimo 2rem, ideal 1rem + 4vw, máximo 3.5rem */
font-size: clamp(2rem, 1rem + 4vw, 3.5rem);
}
.seccion {
padding-block: clamp(3rem, 8vw, 6rem);
}Accesibilidad
No uses sólo vw para el tamaño de texto (font-size: 4vw): el usuario no puede agrandarlo con el zoom. Combínalo siempre con rem dentro de clamp().
Contenedores responsive
css
.contenedor {
width: min(100% - 2rem, 1200px); /* 1rem de margen a los lados en móvil, máx. 1200px */
margin-inline: auto;
}Media queries de preferencias del usuario
Además del tamaño, puedes adaptarte a la configuración del sistema del usuario:
css
/* Modo oscuro del sistema */
@media (prefers-color-scheme: dark) {
:root {
--fondo: #0f172a;
--texto: #e2e8f0;
}
}
/* Usuarios que activaron "reducir movimiento" (mareos, epilepsia, distracción) */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
/* Dispositivos con mouse (hover real) vs. táctiles */
@media (hover: hover) and (pointer: fine) {
.tarjeta:hover { transform: translateY(-4px); }
}
/* Mayor contraste solicitado */
@media (prefers-contrast: more) {
.boton { border: 2px solid currentColor; }
}Hover en móvil
En pantallas táctiles no hay "pasar el mouse": un efecto :hover puede quedarse "pegado" tras tocar. Envolver los efectos decorativos en @media (hover: hover) evita ese problema.
Responsive sin media queries
Muchos componentes se adaptan solos con técnicas intrínsecas que ya conoces:
css
/* Grid que decide cuántas columnas caben */
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr)); gap: 1rem; }
/* Flex que envuelve */
.fila { display: flex; flex-wrap: wrap; gap: 1rem; }
.fila > * { flex: 1 1 300px; }
/* Texto fluido */
h2 { font-size: clamp(1.5rem, 1rem + 2vw, 2.25rem); }Y con container queries un componente se adapta al tamaño de su contenedor, no de la ventana. Lo verás en CSS moderno.
Ejemplo completo: header responsive
html
<header class="header">
<div class="contenedor header__inner">
<a href="/" class="header__logo">Clínica Sonrisa</a>
<button class="header__toggle" aria-expanded="false" aria-controls="menu">☰ <span class="sr-only">Menú</span></button>
<nav id="menu" class="header__nav">
<a href="#servicios">Servicios</a>
<a href="#equipo">Equipo</a>
<a href="#citas" class="header__cta">Agendar cita</a>
</nav>
</div>
</header>css
.header__inner {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
padding-block: 1rem;
}
/* Móvil: menú oculto en columna, ocupando todo el ancho */
.header__nav {
display: none;
flex-basis: 100%;
flex-direction: column;
gap: 0.75rem;
padding-top: 1rem;
}
.header__nav.abierto {
display: flex; /* se muestra al añadir la clase con JavaScript */
}
/* Escritorio: menú en fila y sin botón */
@media (min-width: 768px) {
.header__toggle {
display: none;
}
.header__nav {
display: flex;
flex-basis: auto;
flex-direction: row;
align-items: center;
gap: 2rem;
padding-top: 0;
}
}js
// Abre y cierra el menú en móvil
const boton = document.querySelector('.header__toggle');
const menu = document.querySelector('#menu');
boton.addEventListener('click', () => {
const abierto = menu.classList.toggle('abierto');
boton.setAttribute('aria-expanded', abierto);
});Cómo probar
- DevTools → modo dispositivo (
Ctrl + Shift + M): prueba anchos de 320px, 375px, 768px, 1024px y 1440px. Arrastra el borde para ver todos los anchos intermedios. - En tu celular real: con Live Server en la misma red Wi-Fi, abre
http://IP-de-tu-PC:5500. - Revisa: que no haya scroll horizontal, que los textos sean legibles sin zoom y que los botones tengan al menos 44×44px para tocarlos con el dedo.
Encuentra el culpable del scroll horizontal
Si la página se mueve de lado en móvil, algún elemento es más ancho que la pantalla. Pega temporalmente * { outline: 1px solid red; } para encontrarlo. Causas típicas: width: 100vw, imágenes sin max-width, anchos fijos en px o textos largos sin cortar.
Ejercicios
- Escribe estilos mobile-first para una sección con 1 columna en móvil, 2 desde 640px y 3 desde 1024px.
- Haz que un
h1mida 1.75rem en móvil y crezca de forma fluida hasta 3rem. - Oculta el botón de menú hamburguesa en pantallas de 768px o más.
- Desactiva todas las animaciones para quienes prefieren movimiento reducido.
- Aplica un efecto de elevación a las tarjetas sólo en dispositivos con mouse.
Ver solución
css
/* 1 */
.seccion { display: grid; gap: 1.5rem; }
@media (min-width: 640px) {
.seccion { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
.seccion { grid-template-columns: repeat(3, 1fr); }
}
/* 2 */
h1 { font-size: clamp(1.75rem, 1rem + 3vw, 3rem); }
/* 3 */
@media (min-width: 768px) {
.hamburguesa { display: none; }
}
/* 4 */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* 5 */
@media (hover: hover) {
.tarjeta { transition: transform 0.2s, box-shadow 0.2s; }
.tarjeta:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px rgb(0 0 0 / 0.12);
}
}Resumen
- La meta viewport es obligatoria.
- Mobile-first: estilos base para móvil y
min-widthpara pantallas mayores. - Pon breakpoints donde el diseño se rompe; 2–3 suelen bastar.
- Imágenes con
max-width: 100%,srcsetyobject-fit. clamp()para tipografía y espaciados fluidos (combinandoremyvw).- Respeta las preferencias:
prefers-color-scheme,prefers-reduced-motion,hover. - Prueba en DevTools y en dispositivos reales; nunca debe haber scroll horizontal.
Siguiente: Variables CSS.