Skip to content

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:

  1. Layouts fluidos: medidas relativas (%, fr, flex) en lugar de anchos fijos.
  2. Medios flexibles: imágenes y videos que nunca se desbordan.
  3. 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:

Nombremin-widthDispositivos típicos
(base)0Móviles
sm640pxMóviles grandes horizontal
md768pxTablets
lg1024pxLaptops, tablets horizontal
xl1280pxEscritorio
2xl1536pxPantallas 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:

Layout responsive mobile-first

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 ​

  1. Escribe estilos mobile-first para una sección con 1 columna en móvil, 2 desde 640px y 3 desde 1024px.
  2. Haz que un h1 mida 1.75rem en móvil y crezca de forma fluida hasta 3rem.
  3. Oculta el botón de menú hamburguesa en pantallas de 768px o más.
  4. Desactiva todas las animaciones para quienes prefieren movimiento reducido.
  5. 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-width para pantallas mayores.
  • Pon breakpoints donde el diseño se rompe; 2–3 suelen bastar.
  • Imágenes con max-width: 100%, srcset y object-fit.
  • clamp() para tipografía y espaciados fluidos (combinando rem y vw).
  • 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.

Academia Web — aprende, copia y construye.