Home / Frontend / CSS Grid y Flexbox: cómo crear páginas web responsive paso a paso
CSS Grid y Flexbox: cómo crear páginas web responsive paso a paso

CSS Grid y Flexbox: cómo crear páginas web responsive paso a paso

21 October 2026 · 21 min de lectura ··

Planificar el diseño antes de escribir una sola línea de CSS

Un arquitecto no empieza a levantar paredes sin tener un plano, y una página web no debería empezar a maquetarse sin una idea clara de cómo se distribuyen sus partes. El diseño de una página, o layout, define dónde va la cabecera, cuántas columnas tiene el contenido, cómo se comporta la barra lateral y qué ocurre con todo eso cuando la pantalla se reduce al tamaño de un teléfono.

Durante años, maquetar en CSS fue un ejercicio de ingenio con herramientas que no estaban pensadas para ello: tablas, elementos flotantes, posicionamiento absoluto y trucos con inline-block. Hoy la situación es muy distinta. Flexbox y CSS Grid son sistemas de diseño nativos, compatibles con todos los navegadores modernos desde hace años, y permiten construir interfaces complejas con muy poco código.

En esta guía vamos a aprender cuándo usar cada uno, cómo funcionan sus propiedades principales y cómo combinarlos para construir una página completa: una barra de navegación, una sección hero de dos columnas, una cuadrícula de tarjetas y un pie de página. Después la haremos responsive con media queries, con técnicas que no necesitan media queries y con consultas de contenedor, y terminaremos con los errores más habituales y cómo depurarlos.

Antes de abrir el editor, conviene dibujar el diseño, aunque sea a mano en un papel. Identifica los bloques principales, decide qué se coloca en fila y qué en columnas, y piensa cómo se reorganizará en pantallas pequeñas. Ese boceto te dirá en qué partes necesitas Flexbox y en cuáles Grid.

Flexbox y Grid: una dimensión frente a dos

La diferencia fundamental entre ambos sistemas es el número de dimensiones que controlan.

Flexbox es un sistema unidimensional. Organiza los elementos a lo largo de un único eje, ya sea una fila o una columna, y se encarga de distribuir el espacio entre ellos. Es ideal para componentes: una barra de navegación, un grupo de botones, una tarjeta con su icono y su texto, o un formulario en línea.

CSS Grid es un sistema bidimensional. Define filas y columnas a la vez y coloca los elementos en las celdas resultantes. Es la herramienta adecuada para la estructura general de una página, para galerías y para cualquier diseño en el que necesites alinear elementos tanto en horizontal como en vertical.

Una forma práctica de decidir es preguntarse de dónde parte el diseño. Con Flexbox, el contenido manda: los elementos ocupan el espacio que necesitan y el contenedor reparte lo que sobra. Con Grid, la estructura manda: primero defines la cuadrícula y luego colocas el contenido en ella.

/* Componente en una sola dirección: Flexbox */
.acciones {
    display: flex;
    gap: 0.75rem;
}

/* Estructura en filas y columnas: Grid */
.pagina {
    display: grid;
    grid-template-columns: 240px 1fr;
    grid-template-rows: auto 1fr auto;
}

No se trata de elegir uno para todo el proyecto. Las mejores maquetaciones combinan ambos: Grid para el esqueleto de la página y Flexbox para los componentes que viven dentro de cada celda.

Fundamentos de Flexbox: contenedor, elementos y ejes

Para usar Flexbox basta con aplicar display: flex a un elemento. Ese elemento se convierte en el contenedor flexible y sus hijos directos pasan a ser elementos flexibles. Es importante recordar que solo afecta a los hijos directos, no a los nietos.

<div class="contenedor">
    <div class="caja">Uno</div>
    <div class="caja">Dos</div>
    <div class="caja">Tres</div>
</div>
.contenedor {
    display: flex;
}

Con esa única línea, las tres cajas pasan de apilarse verticalmente a colocarse una junto a otra. Esto ocurre porque Flexbox trabaja con dos ejes. El eje principal y el transversal determinan cómo se distribuyen y alinean los elementos. Por defecto, el eje principal es horizontal y el transversal, vertical.

La propiedad flex-direction cambia la orientación del eje principal:

.contenedor {
    display: flex;
    flex-direction: row; /* valor por defecto: de izquierda a derecha */
    /* flex-direction: column;         de arriba abajo */
    /* flex-direction: row-reverse;    de derecha a izquierda */
    /* flex-direction: column-reverse; de abajo arriba */
}

Al cambiar a column, el eje principal pasa a ser vertical y el transversal, horizontal. Esto es clave para entender las propiedades de alineación, porque su efecto depende del eje sobre el que actúan, no de la dirección horizontal o vertical en sí.

Por defecto, los elementos flexibles intentan caber en una sola línea, encogiéndose si hace falta. Si prefieres que pasen a la siguiente línea cuando no haya espacio, usa flex-wrap:

.contenedor {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

La propiedad gap, que durante un tiempo solo funcionaba en Grid, hoy es compatible con Flexbox en todos los navegadores modernos y sustituye con ventaja a los márgenes entre elementos.

Alinear y repartir el espacio con Flexbox

Las dos propiedades de alineación más usadas en Flexbox son justify-content y align-items.

justify-content reparte el espacio sobrante a lo largo del eje principal:

.contenedor {
    display: flex;
    justify-content: flex-start; /* todos al inicio */
    /* justify-content: center;         todos al centro */
    /* justify-content: flex-end;       todos al final */
    /* justify-content: space-between;  primero y último en los extremos */
    /* justify-content: space-around;   espacio alrededor de cada elemento */
    /* justify-content: space-evenly;   espacios exactamente iguales */
}

align-items alinea los elementos en el eje transversal:

.contenedor {
    display: flex;
    align-items: stretch; /* valor por defecto: ocupan toda la altura */
    /* align-items: center;     centrados verticalmente */
    /* align-items: flex-start; arriba */
    /* align-items: flex-end;   abajo */
    /* align-items: baseline;   alineados por la línea base del texto */
}

Combinando ambas, centrar un elemento en horizontal y vertical, el clásico problema de CSS, se resuelve en tres líneas:

.centrado {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
}

Si un elemento concreto necesita una alineación distinta, align-self sobrescribe el valor del contenedor solo para él. Y un truco muy útil es margin-left: auto o margin-inline-start: auto, que empuja el elemento y todos los que le siguen hacia el final del eje.

El tamaño de cada elemento se controla con la propiedad abreviada flex, que combina tres valores: flex-grow, cuánto crece si sobra espacio; flex-shrink, cuánto encoge si falta; y flex-basis, su tamaño inicial:

.barra-lateral {
    flex: 0 0 260px; /* no crece, no encoge, mide 260px */
}

.contenido {
    flex: 1; /* ocupa todo el espacio sobrante */
}

.columna {
    flex: 1 1 300px; /* parte de 300px, crece y encoge según el espacio */
}

Construir una barra de navegación con Flexbox

Pongamos todo esto en práctica con la cabecera de una tienda de café ficticia. Tendrá el logotipo a la izquierda, el menú en el centro y los botones de acceso a la derecha:

<header class="cabecera">
    <a class="logo" href="/">Tostadero</a>

    <nav class="menu" aria-label="Principal">
        <a href="/cafes">Cafés</a>
        <a href="/metodos">Métodos</a>
        <a href="/suscripcion">Suscripción</a>
        <a href="/blog">Blog</a>
    </nav>

    <div class="cuenta">
        <a class="boton boton--secundario" href="/entrar">Entrar</a>
        <a class="boton" href="/registro">Crear cuenta</a>
    </div>
</header>
.cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 2rem;
    padding: 1rem clamp(1rem, 4vw, 3rem);
    border-bottom: 1px solid #e5e2dc;
}

.logo {
    font-weight: 800;
    font-size: 1.4rem;
    text-decoration: none;
    color: #3b2414;
}

.menu {
    display: flex;
    gap: 1.5rem;
}

.menu a {
    color: #4a4a4a;
    text-decoration: none;
}

.cuenta {
    display: flex;
    gap: 0.75rem;
}

.boton {
    padding: 0.6rem 1.1rem;
    border-radius: 999px;
    background: #3b2414;
    color: #fff;
    text-decoration: none;
}

.boton--secundario {
    background: transparent;
    color: #3b2414;
    border: 1px solid currentColor;
}

La cabecera es un contenedor flexible con tres hijos. justify-content: space-between coloca el logotipo y los botones en los extremos y deja el menú en medio, mientras que align-items: center los alinea verticalmente aunque tengan alturas distintas. El menú y el grupo de botones son, a su vez, contenedores flexibles anidados con su propio gap.

Fíjate también en la función clamp del relleno horizontal: establece un mínimo de 1rem, un máximo de 3rem y un valor intermedio proporcional al ancho de la ventana. Es una forma sencilla de que el espaciado se adapte sin escribir media queries.

Fundamentos de CSS Grid: filas, columnas y unidades fr

Grid se activa con display: grid en el contenedor, igual que Flexbox. La diferencia es que, a continuación, definimos explícitamente la estructura de columnas y filas:

.cuadricula {
    display: grid;
    grid-template-columns: 200px 200px 200px;
    grid-template-rows: 120px auto;
    gap: 1rem;
}

Las medidas fijas son poco flexibles, por eso Grid introdujo la unidad fr, que representa una fracción del espacio disponible. Combinada con las unidades fr y la función minmax, permite crear columnas que se adaptan sin cálculos manuales:

.tres-columnas {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr; /* tres columnas iguales */
}

.columnas-proporcionales {
    display: grid;
    grid-template-columns: 2fr 1fr; /* la primera, el doble que la segunda */
}

.mixtas {
    display: grid;
    grid-template-columns: 240px 1fr; /* una fija y otra flexible */
}

Para no repetir valores, existe la función repeat, y para establecer límites, minmax:

.galeria {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-auto-rows: minmax(180px, auto);
    gap: 1.25rem;
}

En este ejemplo, las filas que Grid crea automáticamente miden como mínimo 180 píxeles y crecen si su contenido lo necesita.

Los elementos se colocan por defecto en orden, celda a celda. Para posicionarlos con precisión se usan las líneas de la cuadrícula, que se numeran empezando por 1:

.destacado {
    grid-column: 1 / 3; /* desde la línea 1 hasta la 3: ocupa dos columnas */
    grid-row: span 2; /* ocupa dos filas */
}

.ancho-completo {
    grid-column: 1 / -1; /* de la primera a la última línea */
}

El valor -1 hace referencia a la última línea, lo que permite que un elemento ocupe todo el ancho sin conocer el número de columnas.

En Grid, justify-items y align-items alinean el contenido dentro de cada celda, mientras que justify-content y align-content alinean la cuadrícula completa dentro del contenedor cuando sobra espacio. La propiedad abreviada place-items: center centra el contenido en ambas direcciones.

Maquetar una página completa con áreas con nombre

La forma más legible de describir la estructura de una página con Grid es nombrar sus áreas. Primero asignas un nombre a cada bloque y después dibujas la distribución como si fuera un mapa de texto:

<body class="layout">
    <header class="zona-cabecera">...</header>
    <nav class="zona-lateral">...</nav>
    <main class="zona-principal">...</main>
    <aside class="zona-extra">...</aside>
    <footer class="zona-pie">...</footer>
</body>
.layout {
    display: grid;
    grid-template-columns: 220px 1fr 260px;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
        "cabecera  cabecera   cabecera"
        "lateral   principal  extra"
        "pie       pie        pie";
    min-height: 100vh;
    gap: 1.5rem;
}

.zona-cabecera {
    grid-area: cabecera;
}
.zona-lateral {
    grid-area: lateral;
}
.zona-principal {
    grid-area: principal;
}
.zona-extra {
    grid-area: extra;
}
.zona-pie {
    grid-area: pie;
}

La estructura se lee de un vistazo, y cambiarla para pantallas pequeñas es tan sencillo como redibujar el mapa. La fila central usa 1fr y el contenedor min-height: 100vh, de modo que el pie de página queda siempre abajo aunque haya poco contenido.

Un punto en la plantilla, como "cabecera . extra", deja una celda vacía. Y todas las filas del mapa deben tener el mismo número de columnas, y cada área debe formar un rectángulo; si no se cumple, el navegador ignora la declaración entera.

Una sección hero de dos columnas con Grid

Volvamos a la tienda de café y construyamos la sección principal: texto y llamada a la acción a un lado, imagen al otro, y una fila de logotipos de cafeterías asociadas debajo del texto.

<section class="hero">
    <div class="hero__texto">
        <h1>Café de especialidad recién tostado, en tu puerta cada mes</h1>
        <p>
            Seleccionamos lotes de pequeños productores y los tostamos la semana
            del envío.
        </p>
        <a class="boton" href="/suscripcion">Empezar suscripción</a>

        <ul class="socios" aria-label="Cafeterías que confían en nosotros">
            <li>
                <img
                    src="socio-1.svg"
                    alt="Café Norte"
                    width="96"
                    height="32"
                />
            </li>
            <li>
                <img
                    src="socio-2.svg"
                    alt="La Molienda"
                    width="96"
                    height="32"
                />
            </li>
            <li>
                <img src="socio-3.svg" alt="Barra 9" width="96" height="32" />
            </li>
        </ul>
    </div>

    <img
        class="hero__imagen"
        src="hero.webp"
        alt="Granos de café recién tostados"
        width="720"
        height="640"
    />
</section>
.hero {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: clamp(2rem, 5vw, 5rem);
    padding: clamp(2rem, 6vw, 6rem) clamp(1rem, 4vw, 3rem);
}

.hero__texto h1 {
    font-size: clamp(2rem, 4vw + 1rem, 3.5rem);
    line-height: 1.1;
}

.hero__imagen {
    width: 100%;
    height: auto;
    border-radius: 1.5rem;
    object-fit: cover;
}

.socios {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    margin-top: 2.5rem;
    padding: 0;
    list-style: none;
}

Aquí se ve con claridad el reparto de papeles: Grid define las dos columnas de la sección y Flexbox organiza la fila de logotipos dentro de la primera columna. align-items: center centra verticalmente el bloque de texto frente a la imagen, y los atributos width y height de la imagen reservan su espacio antes de que cargue, evitando saltos de contenido.

Hacer el diseño responsive con media queries

Un diseño responsive se adapta al tamaño de la pantalla. La técnica clásica son las media queries, que aplican estilos solo cuando se cumplen ciertas condiciones.

La estrategia recomendada es empezar por el móvil, porque es el diseño más sencillo, y añadir complejidad a medida que hay más espacio. Este enfoque de media queries mobile first suele producir menos código y menos sobrescrituras:

/* Base: una sola columna para pantallas pequeñas */
.hero {
    display: grid;
    grid-template-columns: 1fr;
    gap: 2rem;
}

.layout {
    display: grid;
    grid-template-areas:
        "cabecera"
        "principal"
        "extra"
        "lateral"
        "pie";
}

/* A partir de tablets */
@media (width >= 48rem) {
    .hero {
        grid-template-columns: 1fr 1fr;
    }
}

/* A partir de escritorio */
@media (width >= 64rem) {
    .layout {
        grid-template-columns: 220px 1fr 260px;
        grid-template-areas:
            "cabecera  cabecera   cabecera"
            "lateral   principal  extra"
            "pie       pie        pie";
    }
}

La sintaxis de rangos, width >= 48rem, es más legible que la antigua min-width: 48rem y está disponible en todos los navegadores modernos. Usar rem en lugar de píxeles hace que los puntos de corte respeten el tamaño de letra configurado por el usuario.

La barra de navegación también necesita adaptarse. En móvil es habitual ocultar el menú tras un botón, pero una alternativa que no requiere JavaScript es permitir que la cabecera pase a varias líneas:

.cabecera {
    flex-wrap: wrap;
}

@media (width < 48rem) {
    .menu {
        order: 3;
        width: 100%;
        overflow-x: auto;
        padding-block: 0.5rem;
    }
}

En pantallas pequeñas, el menú pasa a una tercera línea que ocupa todo el ancho y se puede desplazar horizontalmente. Si prefieres el clásico menú desplegable, el elemento details o la API Popover del navegador permiten implementarlo con muy poco código.

Elige los puntos de corte en función del contenido y no de dispositivos concretos: añade una media query donde tu diseño empiece a verse mal, no donde creas que termina un modelo de teléfono.

Cuadrículas que se adaptan sin media queries

Una de las técnicas más potentes de Grid permite crear cuadrículas que deciden por sí solas cuántas columnas caben. Este patrón con repeat y auto-fit se ha convertido en un estándar para listados de tarjetas:

.productos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
    gap: 1.5rem;
}

La declaración se lee así: crea tantas columnas como quepan, cada una con un mínimo de 16rem y un máximo de una fracción del espacio. En un móvil habrá una columna, en una tablet dos o tres y en un monitor ancho cuatro o más, sin una sola media query. La función min(100%, 16rem) evita que, en pantallas más estrechas que 16rem, la columna desborde el contenedor.

La diferencia entre auto-fit y auto-fill aparece cuando hay pocos elementos. auto-fit colapsa las columnas vacías y estira los elementos existentes para ocupar todo el ancho; auto-fill mantiene las columnas vacías, de modo que los elementos conservan su tamaño:

/* Con 2 tarjetas en una pantalla ancha: */
.estiradas {
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
} /* 2 tarjetas anchas */
.fijas {
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
} /* 2 tarjetas + huecos */

Flexbox tiene un patrón equivalente para cuando el número de elementos por fila no necesita alinearse en columnas estrictas:

.etiquetas {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.etiquetas > * {
    flex: 1 1 10rem;
}

La diferencia es visible en la última fila: en Grid, los elementos se alinean con las columnas superiores; en Flexbox, se estiran para llenar la línea.

Consultas de contenedor y subgrid

Las media queries responden al tamaño de la ventana, pero un componente no siempre sabe cuánto espacio tiene: la misma tarjeta puede aparecer en la columna principal o en una barra lateral estrecha. Las consultas de contenedor en CSS resuelven esto permitiendo que un componente se adapte al tamaño de su contenedor:

.tarjeta-contenedor {
    container-type: inline-size;
    container-name: tarjeta;
}

.tarjeta {
    display: grid;
    gap: 1rem;
}

@container tarjeta (width >= 28rem) {
    .tarjeta {
        grid-template-columns: 10rem 1fr;
        align-items: center;
    }
}

La tarjeta muestra la imagen encima del texto cuando su contenedor es estrecho y la coloca al lado cuando hay espacio, sin importar el tamaño de la ventana. Las consultas de contenedor son compatibles con todos los navegadores principales desde 2023, al igual que subgrid.

subgrid resuelve otro problema clásico: alinear el contenido interno de varias tarjetas. Cuando cada tarjeta es una cuadrícula independiente, sus títulos, textos y botones quedan a alturas distintas si los textos tienen longitudes diferentes. Con subgrid, las filas internas de cada tarjeta heredan las del contenedor padre:

.productos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 1.5rem;
}

.producto {
    display: grid;
    grid-row: span 4;
    grid-template-rows: subgrid;
    gap: 0.75rem;
}
<article class="producto">
    <img
        src="etiopia.webp"
        alt="Bolsa de café de Etiopía"
        width="400"
        height="300"
    />
    <h3>Etiopía Guji</h3>
    <p>
        Notas florales, bergamota y té negro. Tueste claro, ideal para filtro.
    </p>
    <a class="boton" href="/cafes/etiopia-guji">Añadir</a>
</article>

Cada tarjeta ocupa cuatro filas de la cuadrícula padre, y todas las imágenes, títulos, descripciones y botones quedan perfectamente alineados entre tarjetas de la misma fila.

En el horizonte también está la maquetación tipo mosaico, conocida como masonry, que el grupo de trabajo de CSS está estandarizando con el nombre de Grid Lanes. Algunos navegadores ya la han empezado a implementar, pero antes de usarla en producción conviene comprobar su compatibilidad actual y ofrecer una cuadrícula normal como alternativa.

Combinar Grid y Flexbox en un mismo componente

En proyectos reales, Grid y Flexbox aparecen anidados constantemente. Un patrón muy común es la tarjeta con el botón siempre pegado al fondo, aunque el texto tenga longitudes distintas:

.planes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
    gap: 1.5rem;
}

.plan {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    padding: 1.5rem;
    border: 1px solid #e5e2dc;
    border-radius: 1rem;
}

.plan__accion {
    margin-top: auto;
}

Grid reparte las tarjetas en columnas y estira todas las de una fila hasta la misma altura. Dentro de cada tarjeta, Flexbox en columna apila el contenido, y margin-top: auto empuja el botón hasta el final.

Otro patrón habitual es el llamado holy grail, una página con cabecera, pie y contenido central con dos barras laterales, que ya hemos resuelto con áreas con nombre. Y el diseño de barra lateral que se coloca encima del contenido cuando no hay espacio puede resolverse con Flexbox sin media queries:

.con-lateral {
    display: flex;
    flex-wrap: wrap;
    gap: 2rem;
}

.con-lateral > aside {
    flex: 1 1 15rem;
}

.con-lateral > main {
    flex: 999 1 30rem;
}

El valor de crecimiento tan alto del contenido principal hace que acapare casi todo el espacio sobrante, mientras que flex-wrap envía la barra lateral a una nueva línea cuando no caben ambos con sus tamaños base.

Accesibilidad: el orden visual y el orden del documento

Grid y Flexbox permiten colocar los elementos en un orden visual distinto al del HTML, con propiedades como order, grid-area, flex-direction: row-reverse o la colocación por líneas. Es una capacidad potente, pero tiene un coste si se usa sin cuidado.

Los lectores de pantalla y la navegación con teclado siguen el orden del documento, no el visual. Si separas demasiado el orden visual y el del DOM, un usuario que navega con la tecla Tab verá cómo el foco salta de forma aparentemente aleatoria por la página:

/* Cuidado: visualmente la imagen va primero, pero en el teclado va después */
.hero__imagen {
    order: -1;
}

La recomendación es que el HTML refleje el orden lógico de lectura y usar la reordenación solo para ajustes visuales que no alteren el significado, como colocar una imagen decorativa a la izquierda o a la derecha. Si en móvil necesitas un orden de lectura completamente distinto, replantea la estructura del HTML.

Otras recomendaciones de accesibilidad relacionadas con el layout son usar elementos semánticos como header, nav, main, aside y footer, que los lectores de pantalla utilizan para navegar; evitar alturas fijas en contenedores con texto, que se desbordan cuando el usuario aumenta el tamaño de letra; y comprobar que el diseño funciona con un zoom del 200 por ciento.

Errores comunes y cómo solucionarlos

El primer error es aplicar propiedades al elemento equivocado. justify-content, align-items, gap o grid-template-columns van en el contenedor; flex, align-self, grid-column o grid-area van en los hijos. Si una propiedad no hace nada, comprueba en qué nivel está.

El segundo es esperar que Flexbox o Grid afecten a los nietos. Solo los hijos directos del contenedor se convierten en elementos flexibles o de cuadrícula. Si hay un div intermedio, ese div es el único elemento colocado. La declaración display: contents puede eliminar una caja intermedia, pero úsala con precaución porque en algunos casos afecta a la semántica para las tecnologías de asistencia.

El tercero es el desbordamiento de texto largo o de elementos como tablas y bloques de código dentro de columnas 1fr o elementos con flex: 1. Por defecto, estos elementos no pueden encogerse por debajo del tamaño mínimo de su contenido:

/* El bloque de código desborda la columna */
.contenido {
    flex: 1;
}

/* Solución: permitir que el elemento encoja */
.contenido {
    flex: 1;
    min-width: 0;
}

/* En Grid, usar minmax con 0 en lugar de 1fr a secas */
.layout {
    grid-template-columns: 220px minmax(0, 1fr);
}

El cuarto es usar alturas fijas, como height: 500px, en secciones con contenido variable. En cuanto el texto crece, el contenido se desborda. Usa min-height o deja que el contenido determine la altura.

El quinto es confundir justify-content y align-items tras cambiar flex-direction a column. Con la columna como eje principal, justify-content actúa en vertical y align-items en horizontal.

El sexto es usar 100vh en móviles, donde las barras del navegador aparecen y desaparecen. Las unidades dvh, svh y lvh tienen en cuenta esas barras y son la alternativa recomendada para secciones de pantalla completa:

.portada {
    min-height: 100dvh;
}

El séptimo es crear una plantilla de áreas no válida, con filas de distinto número de columnas o áreas en forma de L. El navegador descarta la declaración sin avisar, así que, si el diseño se ve desordenado de repente, revisa el mapa de áreas.

Depurar layouts con las herramientas del navegador

Las herramientas para desarrolladores de Chrome, Edge, Firefox y Safari incluyen inspectores específicos para Grid y Flexbox que ahorran mucho tiempo.

En el panel de elementos, los contenedores flexibles y de cuadrícula aparecen marcados con una etiqueta flex o grid. Al pulsarla, el navegador superpone sobre la página las líneas de la cuadrícula con su numeración, los nombres de las áreas, los huecos definidos por gap y el espacio libre de cada contenedor flexible.

Un truco rápido para entender qué está pasando en un diseño es añadir temporalmente un contorno a todos los elementos:

* {
    outline: 1px solid rgb(255 0 0 / 0.4);
}

A diferencia de border, outline no ocupa espacio, por lo que no altera el diseño que intentas depurar.

Para probar el comportamiento responsive, el modo de dispositivo de las herramientas permite simular distintos tamaños de pantalla, pero no sustituye a la prueba en teléfonos reales, donde intervienen las barras del navegador, el teclado virtual y la densidad de píxeles.

Buenas prácticas para producción

Algunas recomendaciones que conviene aplicar en cualquier proyecto:

  • Empieza por el diseño móvil y añade columnas a medida que haya espacio.
  • Usa Grid para la estructura de la página y Flexbox para los componentes.
  • Prefiere gap frente a márgenes para separar elementos dentro de un contenedor.
  • Define tamaños con rem, fr, minmax, clamp y porcentajes antes que con píxeles fijos.
  • Reserva el espacio de las imágenes con width y height o con aspect-ratio para evitar saltos de contenido.
  • Mantén el orden del HTML coherente con el orden visual.
  • Usa consultas de contenedor para componentes reutilizables y media queries para la estructura global.

También es recomendable centralizar los valores repetidos en propiedades personalizadas, de modo que los anchos máximos, los huecos y los puntos de corte del contenido se mantengan coherentes:

:root {
    --ancho-maximo: 72rem;
    --hueco: clamp(1rem, 2vw, 2rem);
}

.envoltorio {
    width: min(100% - 2rem, var(--ancho-maximo));
    margin-inline: auto;
}

.productos {
    gap: var(--hueco);
}

La clase envoltorio limita el ancho del contenido, lo centra y deja un margen lateral de un rem a cada lado en pantallas pequeñas, todo en una sola línea gracias a la función min.

Conclusiones

Flexbox y CSS Grid han convertido la maquetación web en una tarea predecible y expresiva. Flexbox organiza elementos en una sola dirección y reparte el espacio entre ellos, lo que lo hace perfecto para barras de navegación, grupos de botones y el interior de las tarjetas. Grid define filas y columnas a la vez y es la herramienta natural para la estructura de la página, las galerías y cualquier diseño que necesite alineación en dos dimensiones.

Lo más eficaz es combinarlos: Grid para el esqueleto y Flexbox para los componentes. Las áreas con nombre hacen que la estructura se lea como un plano, las unidades fr, minmax y clamp adaptan los tamaños de forma fluida, y el patrón repeat(auto-fit, minmax(...)) crea cuadrículas que se ajustan solas sin media queries.

Para el diseño responsive, el enfoque mobile first con la sintaxis de rangos en las media queries sigue siendo la base, mientras que las consultas de contenedor permiten que cada componente responda a su propio espacio y subgrid alinea el contenido entre tarjetas. Todo ello está disponible hoy en los navegadores modernos.

Por último, recuerda que un buen layout también es accesible: mantén el orden del HTML coherente con el visual, evita alturas fijas y apóyate en los inspectores de Grid y Flexbox del navegador para depurar. Con un boceto previo y estas herramientas, cualquier diseño, por complejo que parezca, se reduce a unas pocas decenas de líneas de CSS.