---
name: diseno-responsivo
description: Diseño responsivo moderno. Container queries, fluid typography, CSS Grid, Flexbox, mobile-first, Tailwind CSS y patrones para interfaces adaptativas.
version: "1.0.0"
herramientasPermitidas: [Read, Grep]
evolvable: true  # default para skill estandar
exclusiones:
  - "No cargar para sistemas de design tokens (paletas de colores, tipografía de marca, theming) — para tokens cargar `design-tokens`."
  - "No cargar para accesibilidad (ARIA, contraste, lector de pantalla) — para a11y cargar `accesibilidad-a11y`."
  - "No cargar para optimización de rendimiento de imágenes en el pipeline de build (WebP, AVIF, compresión) — para imágenes en build cargar el skill de rendimiento del framework."
  - "No cargar para CSS de componentes individuales sin responsividad (estilos fijos de un card o modal) — cargar `css-moderno` para CSS de componente."
---
# Diseño Responsivo Moderno

## Cuándo NO cargar

- La tarea es definir el sistema de design tokens (paletas, tipografía de marca, theming light/dark): cargar `design-tokens`.
- La revisión es de accesibilidad (contraste WCAG, ARIA, lectores de pantalla): cargar `accesibilidad-a11y`.
- La optimización es del pipeline de imágenes en build (WebP, AVIF, lazy loading en Next.js): cargar el skill de rendimiento del framework.
- El CSS es de componentes fijos sin comportamiento adaptativo: cargar `css-moderno`.

## Filosofía mobile-first

El diseño mobile-first significa escribir los estilos base para pantallas pequeñas
y luego agregar complejidad para pantallas más grandes mediante breakpoints.

```css
/* MAL: desktop-first — sobreescribir para móvil es más complejo */
.tarjeta {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}
@media (max-width: 768px) {
  .tarjeta { grid-template-columns: 1fr; }
}

/* BIEN: mobile-first — agregar complejidad progresivamente */
.tarjeta {
  display: grid;
  grid-template-columns: 1fr;
}
@media (min-width: 768px) {
  .tarjeta { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 1024px) {
  .tarjeta { grid-template-columns: 1fr 1fr 1fr; }
}
```

---

## Breakpoints estándar (Tailwind CSS)

```
sm:   640px  — Teléfonos en horizontal
md:   768px  — Tablets
lg:   1024px — Laptops / pantallas pequeñas
xl:   1280px — Desktops
2xl:  1536px — Pantallas grandes
```

```html
<!-- Tailwind mobile-first: sin prefijo = base -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
  <!-- Cards -->
</div>
```

---

## CSS Grid auto-responsive sin breakpoints

```css
.grid-auto-fill {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.5rem;
}
```

Para layouts completos de página con Grid y Flexbox, ver [recursos/ejemplos-layouts.md](recursos/ejemplos-layouts.md).

---

## Container Queries — el futuro del diseño responsivo

Container queries permiten aplicar estilos basados en el tamaño del **contenedor**,
no de la ventana. Esencial para componentes verdaderamente reutilizables.

```css
.card-contenedor {
  container-type: inline-size;
  container-name: card;
}

.card {
  display: flex;
  flex-direction: column;
}

@container card (min-width: 400px) {
  .card {
    flex-direction: row;
  }
  .card-imagen {
    width: 40%;
    flex-shrink: 0;
  }
}

@container card (min-width: 600px) {
  .card-acciones {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
  }
}
```

---

## Tipografía fluida

La tipografía fluida elimina los saltos abruptos de tamaño entre breakpoints.

```css
/* Escala linealmente de 1rem (320px) a 1.5rem (1200px) */
.titulo-principal {
  font-size: clamp(1rem, 0.75rem + 1.25vw, 1.5rem);
}

/* Escala de tipo fluida completa */
:root {
  --text-sm:   clamp(0.75rem,  0.7rem  + 0.25vw, 0.875rem);
  --text-base: clamp(1rem,     0.9rem  + 0.5vw,  1.125rem);
  --text-lg:   clamp(1.125rem, 1rem    + 0.625vw, 1.25rem);
  --text-xl:   clamp(1.25rem,  1.1rem  + 0.75vw,  1.5rem);
  --text-2xl:  clamp(1.5rem,   1.25rem + 1.25vw,  2rem);
  --text-3xl:  clamp(1.875rem, 1.5rem  + 1.875vw, 2.25rem);
}
```

---

## Imágenes responsivas — reglas clave

- Usar `srcset` y `sizes` para servir la imagen del tamaño adecuado.
- SIEMPRE `loading="lazy"` y `decoding="async"` en imágenes fuera del viewport.
- SIEMPRE atributos `width` y `height` para evitar layout shift.
- Usar `<picture>` para art direction (recortes distintos por breakpoint).

Para ejemplos completos de imágenes y patrones Tailwind, ver [recursos/ejemplos-layouts.md](recursos/ejemplos-layouts.md).

---

## Accesibilidad y responsivo — reglas clave

- Botón de menú móvil SIEMPRE con `aria-label`, `aria-expanded` y `aria-controls`.
- Respetar `prefers-reduced-motion: reduce` desactivando animaciones.
- Áreas táctiles mínimas de 44x44px en móvil.

Para ejemplos completos de accesibilidad responsiva, ver [recursos/ejemplos-layouts.md](recursos/ejemplos-layouts.md).

---

## Checklist de diseño responsivo

- [ ] El diseño base está en mobile (sin prefijo en Tailwind).
- [ ] Tipografía usa clamp() o escala fluida.
- [ ] Las imágenes tienen srcset y loading="lazy".
- [ ] Los formularios tienen labels visibles en todas las pantallas.
- [ ] Los botones/links tienen área táctil mínima de 44x44px.
- [ ] No hay overflow horizontal en ningún breakpoint.
- [ ] El espaciado usa variables relativas (rem, em) no píxeles fijos.
- [ ] Se probó en orientación portrait y landscape.
- [ ] Los componentes reutilizables usan container queries donde aplica.

## Gotchas / Errores comunes no obvios

**`container-type: inline-size` en un elemento `position: relative` rompe los `position: fixed` de sus descendientes**: cuando un elemento tiene `container-type`, crea un nuevo contexto de contención que convierte cualquier `position: fixed` dentro de él en `position: absolute` relativo al contenedor. Causa: el spec de CSS Container Queries especifica que los contenedores crean contexto de contención y eso afecta a los elementos fijos. Fix: no usar `container-type` en wrappers que tengan descendientes con `position: fixed` (modales, tooltips, dropdowns). Para esos casos, usar un wrapper contenedor hermano en lugar de padre.

**`clamp()` con unidades `vw` produce tipografía que se escala incorrectamente cuando el usuario hace zoom en el browser**: `font-size: clamp(1rem, 2vw, 2rem)` usa `vw` que es relativo al viewport, no al zoom del usuario. Al hacer zoom al 200%, `vw` se reduce proporcionalmente y la fuente puede quedar más pequeña de lo esperado. Causa: `vw` no respeta el factor de zoom del usuario — es siempre relativo al viewport físico. Fix: usar `vi` (inline size) o combinar con `em` en la expresión media: `clamp(1rem, 0.5rem + 1vw + 0.5em, 2rem)` para que el componente `em` escale con el zoom del usuario.

**El breakpoint `md:` de Tailwind (`768px`) no corresponde al breakpoint de tablet real en 2026**: en 2026, las tablets más comunes tienen resoluciones de `820px` (iPad Air) o `912px` (Surface), no `768px`. Usar `md:` para "layout de tablet" produce un layout desktop que se activa en pantallas de teléfono grande. Causa: los breakpoints de Tailwind son históricos y no reflejan los viewports actuales de dispositivos. Fix: usar container queries en lugar de media queries para componentes que deben adaptarse al espacio disponible, no al tamaño del viewport. Para layouts de página, considerar breakpoints personalizados en `tailwind.config.js` basados en los dispositivos reales del público objetivo.

**`srcset` con `sizes` incorrecto hace que el browser descargue la imagen en resolución incorrecta aunque el `srcset` tenga los tamaños correctos**: `sizes="(max-width: 768px) 100vw, 50vw"` le dice al browser que en desktop la imagen ocupa 50% del viewport. Si la imagen realmente ocupa 33%, el browser descarga una imagen más grande de lo necesario, desperdiciando ancho de banda. Causa: el atributo `sizes` es una instrucción al browser, no un cálculo automático. Fix: medir el ancho real que ocupa la imagen en cada breakpoint con las DevTools y usar ese valor en `sizes`. Un error en `sizes` no rompe el render (el browser usa el `src` como fallback) pero sí afecta el rendimiento.
