Una página que solo se ve bien en la computadora pierde a más de la mitad de sus visitas. Con el diseño responsivo, en esta última lección harás que tus páginas se adapten a cualquier pantalla: diseño fluido, media queries pensando primero en el celular, container queries, variables con modo oscuro e imágenes del tamaño justo. Y al final, una página completa que junta todo el curso.
El primer paso: la etiqueta viewport
Más de la mitad de las visitas a un sitio llegan desde un celular. Una página responsiva es la que se adapta a cualquier ancho de pantalla con el mismo HTML. Todo empieza con una línea que ya pusiste en el esqueleto de la lección 1:
<meta name="viewport" content="width=device-width, initial-scale=1">
Sin ella, los navegadores de los celulares suponen que la página se hizo para una pantalla de computadora: la dibujan con 980 píxeles de ancho y la encogen hasta que cabe, con letras diminutas. Con ella, la página mide lo que mide la pantalla y tus reglas de CSS deciden cómo se acomoda. No pongas maximum-scale=1 ni user-scalable=no: impiden ampliar con los dedos, y hay gente que lo necesita para leer.
Diseño fluido: que nada tenga ancho fijo
Antes de hablar de reglas para cada tamaño de pantalla, la mitad del trabajo se resuelve evitando los anchos fijos. Tres hábitos:
- Imágenes que se encogen:
img { max-width: 100%; height: auto; }. - Contenedores con un ancho máximo, no fijo:
max-width: 60remen vez dewidth: 960px. O, más corto,width: min(100% - 2rem, 60rem), que deja un margen de 1 rem a cada lado en pantallas chicas. - Rejillas que se reacomodan solas, como la de
repeat(auto-fit, minmax(…))de la lección 7.
Letra que crece con la pantalla: clamp()
<h1>Un título que se adapta</h1>
h1 {
font-size: clamp(1.5rem, 4vw + 1rem, 3rem);
font-family: system-ui, sans-serif;
}clamp(mínimo, ideal, máximo) usa el valor ideal mientras quede entre los otros dos. Aquí el ideal crece con el ancho de la ventana (4vw), pero nunca baja de 24 píxeles ni pasa de 48. En una ventana de 720 píxeles de ancho, el título mide 44.8 (4 % de 720 más 16). Sumar un rem al vw no es capricho: así el tamaño sigue respondiendo si la persona agranda la letra de su navegador.
Media queries: reglas para cada tamaño
Cuando el diseño tiene que cambiar de verdad (el menú pasa a otra línea, una columna se convierte en tres), se usan las media queries: bloques de reglas que solo se aplican si se cumple una condición, normalmente el ancho de la ventana.
<div class="tarjetas"> <div>Uno</div><div>Dos</div><div>Tres</div> </div>
.tarjetas {
display: grid;
gap: 8px;
font: 600 16px system-ui, sans-serif;
}
.tarjetas div {
padding: 24px;
background: #1e64af;
color: white;
border-radius: 8px;
}
@media (min-width: 30rem) {
.tarjetas { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 40rem) {
.tarjetas { grid-template-columns: 1fr 1fr 1fr; }
}En un marco de 720 píxeles hay 3 columnas. Ábrelo en el editor y prueba los botones de ancho: con «Celular» (375 px) queda una sola columna, porque no se cumple ninguna de las dos condiciones.
Este estilo se llama mobile first: los estilos sin condición son los del celular, y cada @media (min-width: …) añade cambios para pantallas más grandes. Tiene dos ventajas: el celular, que suele ser el dispositivo más lento, no lee reglas que no le tocan, y obliga a pensar primero en lo esencial. Los puntos de corte se ponen donde el diseño empieza a verse mal, no en los anchos de modelos concretos de teléfono; escribirlos en rem hace que también respondan al tamaño de letra que eligió la persona.
El error típico: la regla del celular no se aplica nunca
<p id="prueba">¿De qué color soy en un celular?</p>
@media (max-width: 40rem) {
p { color: #b91c1c; }
}
p { color: #1e64af; }En el celular (medido con la ventana a 375 píxeles en los tres navegadores) el texto sigue azul. La media query no aumenta la especificidad: la regla de dentro y la de fuera pesan lo mismo y gana la última del código, que es la general (lo viste en la lección 5). Las reglas generales van primero y las @media, después.
Container queries: según el sitio que tiene el componente
Las media queries miran la ventana. Pero una tarjeta puede estar en la columna ancha de una página y también en una barra lateral estrecha, con la misma ventana. Desde 2023, las container queries permiten que un componente se adapte al ancho de su contenedor:
<div class="ancho">
<article class="ficha">
<img src="https://decodigo.com/wp-content/uploads/2026/10/decodigo_placa_raspberry-pi-5.jpg" alt="" width="640" height="420">
<div><h2>Raspberry Pi 5</h2><p>En un contenedor ancho, foto y texto van lado a lado.</p></div>
</article>
</div>
<div class="angosto">
<article class="ficha">
<img src="https://decodigo.com/wp-content/uploads/2026/10/decodigo_placa_raspberry-pi-5.jpg" alt="" width="640" height="420">
<div><h2>Raspberry Pi 5</h2><p>En uno angosto, uno debajo del otro.</p></div>
</article>
</div>.ancho { width: 560px; }
.angosto { width: 240px; margin-top: 12px; }
.ancho, .angosto { container-type: inline-size; }
.ficha { display: grid; gap: 10px; font-family: system-ui, sans-serif; background: #eef3f9; padding: 10px; border-radius: 10px; }
.ficha img { width: 100%; height: auto; border-radius: 6px; }
.ficha h2 { margin: 0; font-size: 1.1rem; }
.ficha p { margin: 4px 0 0; }
@container (min-width: 400px) {
.ficha { grid-template-columns: 200px 1fr; align-items: center; }
}Es el mismo HTML y la misma regla, con resultados distintos: la ficha del contenedor ancho tiene 2 columnas y la del angosto, 1. La clave es container-type: inline-size en el contenedor, que lo convierte en la referencia de las reglas @container de dentro. Funcionan en Chrome y Edge desde la 105, Safari desde la 16 y Firefox desde la 110. Curiosamente, el validador del W3C (Nu Html Checker 26.11.4) todavía no las conoce y marca container-type y @container como errores de CSS; los tres navegadores las aplican sin problema.
Variables de CSS y modo oscuro
Las propiedades personalizadas, que todo el mundo llama variables, guardan un valor con un nombre que empieza por dos guiones y se usa con var(). Sirven para no repetir el mismo color en treinta reglas y, sobre todo, para cambiar muchos valores de golpe:
<main> <h1>Claro u oscuro</h1> <p>Esta página sigue la preferencia de tu sistema. Cambia tu celular o tu computadora a modo oscuro y recarga.</p> <a href="#">Un enlace</a> </main>
:root {
--fondo: #ffffff;
--texto: #33475b;
--acento: #1e64af;
}
@media (prefers-color-scheme: dark) {
:root {
--fondo: #0f1f33;
--texto: #c9d6e4;
--acento: #60a5fa;
}
}
body {
background: var(--fondo);
color: var(--texto);
font-family: system-ui, sans-serif;
}
a { color: var(--acento); }La media query prefers-color-scheme: dark se cumple cuando el sistema está en modo oscuro, y en ella solo se cambian las variables: el resto de la hoja no se toca. Hay otras preferencias igual de útiles, como prefers-reduced-motion: reduce, que activan las personas a las que las animaciones les marean; respétala desactivando las animaciones que no sean imprescindibles.
Imágenes para cada pantalla
Un celular no necesita descargar una foto de 2,000 píxeles de ancho. Con srcset le das al navegador varias versiones de la misma imagen y con sizes le dices qué ancho ocupará en la página; él elige la más adecuada para la pantalla y su densidad de píxeles:
<img src="foto-800.jpg"
srcset="foto-400.jpg 400w, foto-800.jpg 800w, foto-1600.jpg 1600w"
sizes="(min-width: 60rem) 50vw, 100vw"
alt="Fachada del café" width="1600" height="1067"
loading="lazy">Y loading="lazy" retrasa la descarga de las imágenes hasta que el lector se acerca a ellas al bajar por la página. No la pongas en la imagen principal de arriba, que tiene que salir cuanto antes. Para servir formatos distintos (AVIF a quien lo entienda, JPEG al resto) o recortes distintos según el tamaño, está el elemento <picture>; lo verás en el ejemplo de imágenes responsivas.
El proyecto: una página completa
Para terminar el curso, todo junto en una sola página: el esqueleto de la lección 1, etiquetas semánticas, una cabecera con Flexbox, un título con clamp(), una rejilla que se adapta sola, variables con modo oscuro y una animación que respeta prefers-reduced-motion. Es un documento completo, válido según el validador del W3C, que puedes copiar, guardar como index.html y abrir:
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Café La Esquina</title>
<style>
:root {
--fondo: #ffffff;
--texto: #33475b;
--titulo: #0f1f33;
--acento: #1e64af;
--suave: #eef3f9;
}
@media (prefers-color-scheme: dark) {
:root {
--fondo: #0f1f33;
--texto: #c9d6e4;
--titulo: #ffffff;
--acento: #60a5fa;
--suave: #1b2f47;
}
}
*, *::before, *::after { box-sizing: border-box; }
body {
margin: 0;
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
line-height: 1.6;
color: var(--texto);
background: var(--fondo);
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--acento); }
.contenedor { width: min(100% - 2rem, 60rem); margin-inline: auto; }
.cabecera { padding-block: 1rem; }
.cabecera .contenedor {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: 0.5rem 1.5rem;
}
.logo { font-weight: 800; color: var(--titulo); text-decoration: none; }
.menu { display: flex; gap: 1rem; }
.portada { padding-block: 2rem; }
.portada h1 {
font-size: clamp(2rem, 5vw + 1rem, 3.5rem);
line-height: 1.1;
color: var(--titulo);
margin: 0 0 0.5rem;
}
.boton {
display: inline-block;
padding: 0.7em 1.3em;
border-radius: 0.6em;
background: var(--acento);
color: var(--fondo);
font-weight: 700;
text-decoration: none;
}
.platillos {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
gap: 1rem;
padding: 0;
list-style: none;
}
.platillo {
background: var(--suave);
border-radius: 12px;
overflow: hidden;
}
.platillo div { padding: 0.8rem 1rem 1rem; }
.platillo h3 { margin: 0; color: var(--titulo); }
.platillo p { margin: 0.2rem 0 0; }
.pie { padding-block: 2rem; margin-top: 2rem; background: var(--suave); }
@media (min-width: 48rem) {
.portada { padding-block: 4rem; }
}
@media (prefers-reduced-motion: no-preference) {
.boton { transition: transform 0.15s; }
.boton:hover { transform: translateY(-2px); }
}
</style>
</head>
<body>
<header class="cabecera">
<div class="contenedor">
<a class="logo" href="#">Café La Esquina</a>
<nav class="menu" aria-label="Principal">
<a href="#menu">Menú</a>
<a href="#visitanos">Visítanos</a>
</nav>
</div>
</header>
<main>
<section class="portada">
<div class="contenedor">
<h1>Café de Veracruz, tostado cada semana</h1>
<p>Desayunos, pan dulce y el mejor café de olla de la colonia.</p>
<a class="boton" href="#visitanos">Cómo llegar</a>
</div>
</section>
<section id="menu" class="contenedor">
<h2>Lo más pedido</h2>
<ul class="platillos">
<li class="platillo">
<img src="https://decodigo.com/wp-content/uploads/2026/10/decodigo_placa_raspberry-pi-5.jpg" alt="" width="640" height="420">
<div><h3>Café de olla</h3><p>Con canela y piloncillo. $45 MXN</p></div>
</li>
<li class="platillo">
<img src="https://decodigo.com/wp-content/uploads/2026/10/decodigo_placa_raspberry-pi-5.jpg" alt="" width="640" height="420">
<div><h3>Chilaquiles</h3><p>Verdes o rojos, con huevo. $95 MXN</p></div>
</li>
<li class="platillo">
<img src="https://decodigo.com/wp-content/uploads/2026/10/decodigo_placa_raspberry-pi-5.jpg" alt="" width="640" height="420">
<div><h3>Concha</h3><p>De vainilla o chocolate. $22 MXN</p></div>
</li>
</ul>
</section>
</main>
<footer id="visitanos" class="pie">
<div class="contenedor">
<h2>Visítanos</h2>
<address>Calle 5 de Mayo 12, Centro. Lunes a sábado, de 8 a 20 h.</address>
</div>
</footer>
</body>
</html>Ábrelo en el editor y prueba los tres anchos. Con la ventana a 375 píxeles, como un celular, los platillos van en 1 columna y la página no se desborda de lado (comprobado en los tres navegadores); con más ancho caben dos o tres por fila, y el menú se acomoda solo. Ningún tamaño está escrito a mano en píxeles salvo los radios de las esquinas.
Retos
Reto 1. Haz que un menú de navegación sea una columna en el celular y una fila a partir de 40 rem, con mobile first.
Ver la solución
<nav class="menu"> <a href="#">Inicio</a> <a href="#">Servicios</a> <a href="#">Contacto</a> </nav>
.menu {
display: flex;
flex-direction: column;
gap: 0.5rem;
font-family: system-ui, sans-serif;
}
@media (min-width: 40rem) {
.menu { flex-direction: row; gap: 1.5rem; }
}Reto 2. Define con variables un tema de colores y añade una clase .tema-sepia en el body que cambie solo las variables a un fondo crema y texto café.
Ver la solución
<div class="tema-sepia"> <h1>Modo lectura</h1> <p>El tema cambia con una sola clase.</p> </div>
:root { --fondo: #ffffff; --texto: #0f1f33; }
.tema-sepia { --fondo: #f4ecd8; --texto: #5b4636; }
.tema-sepia, body {
background: var(--fondo);
color: var(--texto);
font-family: Georgia, serif;
padding: 1rem;
}Las variables se heredan como el color o la letra, así que redefinirlas en un elemento cambia el aspecto de todo lo que tiene dentro.
Reto 3. La página del proyecto se ve bien, pero un usuario dice que en su celular «tiene que mover la página de lado». ¿Qué tres cosas revisarías primero?
Ver la solución
1) Que esté la etiqueta meta viewport. 2) Que ningún elemento tenga un width fijo en píxeles mayor que la pantalla (imágenes sin max-width: 100%, tablas, bloques de código, un iframe de video). 3) Que no haya una palabra o dirección larguísima dentro de un elemento flex sin min-width: 0 ni overflow-wrap, como en la lección 7. En las herramientas del navegador, el modo de dispositivo (Ctrl+Shift+M en Chrome y Firefox) permite ver la página a cualquier ancho y encontrar al culpable.
Terminaste el curso
Ya sabes escribir HTML que se entiende, darle forma con CSS y hacer que se adapte a cualquier pantalla. Para comprobarlo, haz el test de 24 preguntas, en el que tienes que adivinar qué se ve; repasa las rarezas de CSS, que explican los comportamientos que más desconciertan, y usa los ejemplos como recetario para tus proyectos.
Cada fragmento de HTML de esta lección pasó por el Nu Html Checker 26.11.4, el validador oficial del W3C, y cada resultado se pintó en Chromium, Firefox y WebKit (los motores de Chrome, Firefox y Safari); las cifras del texto se midieron en los tres. ¿Quieres probar algo? Usa el editor de HTML y CSS. Logotipos de HTML5 (W3C) y CSS3 (Rudloff) en la imagen de la página: Wikimedia Commons, CC BY 3.0.
