Hasta aquí cada elemento iba debajo del anterior. Flexbox y Grid son las dos herramientas de CSS para colocar elementos en filas, columnas y rejillas, y con ellas se hace hoy la estructura de casi cualquier página. En esta lección verás cuándo usar cada una, las cuatro o cinco propiedades que resuelven el 90 % de los casos y, al final, lo justo de position para los elementos que se salen del flujo.
Flexbox: elementos en una fila (o en una columna)
Durante años, poner tres cajas una al lado de otra exigía trucos con float o con tablas. Hoy basta con una línea: display: flex en el contenedor. Sus hijos directos pasan a ser elementos flexibles y se colocan en fila.
<div class="c"> <div>Uno</div> <div>Dos</div> <div>Tres</div> </div>
.c { display: flex; gap: 8px; padding: 8px; background: #eef3f9; border-radius: 8px; margin-bottom: 10px; }
.c div { padding: 10px 14px; background: #1e64af; color: white; border-radius: 6px; font: 600 15px system-ui, sans-serif; }Flexbox trabaja sobre dos ejes. El principal es la dirección en la que se colocan los elementos (por omisión, en fila de izquierda a derecha) y el cruzado es el perpendicular.
Repartir y alinear
justify-contentReparte en el eje principal:flex-start(al principio),center,flex-end,space-between(el espacio sobrante entre ellos) ospace-evenly.align-itemsAlinea en el eje cruzado:stretch(estirados a la misma altura, el valor por omisión),flex-start,centeroflex-end.gapEl espacio entre elementos. Mucho mejor que poner márgenes a cada uno.flex-directionrow(fila) ocolumn(columna).flex-wrap: wrapSi no caben, pasan a la línea siguiente en vez de apretarse.
<header class="barra">
<strong>mi sitio</strong>
<nav>
<a href="#">Inicio</a>
<a href="#">Blog</a>
<a href="#">Contacto</a>
</nav>
</header>.barra {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
background: #0f1f33;
color: white;
font-family: system-ui, sans-serif;
}
.barra nav {
display: flex;
gap: 16px;
}
.barra a { color: white; }La barra de navegación clásica: el nombre a la izquierda, el menú a la derecha (space-between, que deja el menú a 16 píxeles del borde, justo el padding) y todo centrado en vertical. El menú es a su vez otro contenedor flex: se pueden anidar sin límite.
Centrar, por fin
<div class="escena"> <div class="tarjeta">Justo en medio</div> </div>
.escena {
display: flex;
justify-content: center;
align-items: center;
height: 180px;
background: #eef3f9;
}
.tarjeta {
padding: 16px 24px;
background: white;
border-radius: 10px;
font-family: system-ui, sans-serif;
}Centrar algo en horizontal y en vertical fue durante quince años el chiste recurrente del diseño web. Con Flexbox son dos propiedades. En el ejemplo de centrar un elemento están todas las formas y cuándo usar cada una.
Que unos crezcan y otros no
La propiedad flex va en los hijos y dice cómo se reparten el espacio sobrante. flex: 1 significa «crece para ocupar lo que quede»; si dos elementos tienen flex: 1 y otro flex: 2, el último se queda el doble de ese sobrante.
<div class="c"> <div class="fijo">Fijo</div> <div class="crece">Crece (flex: 1)</div> <div class="fijo">Fijo</div> </div> <form class="c buscar"> <input aria-label="Buscar" placeholder="Buscar…"> <button>Ir</button> </form>
.c { display: flex; gap: 8px; padding: 8px; background: #eef3f9; border-radius: 8px; margin-bottom: 10px; }
.c div { padding: 10px 14px; background: #1e64af; color: white; border-radius: 6px; font: 600 15px system-ui, sans-serif; }
.crece { flex: 1; }
.buscar input { flex: 1; font: inherit; padding: 8px; }El buscador es el caso más útil: el campo se estira y el botón conserva su tamaño, a cualquier ancho.
El error típico: un texto largo que rompe la fila
<div class="fila"> <img src="https://decodigo.com/wp-content/uploads/2026/10/decodigo_placa_raspberry-pi-5.jpg" alt="" width="60" height="40"> <div class="texto">https://www.ejemplo.com.mx/una/direccion/muy/larga/que/no/se/puede/partir</div> </div>
.fila {
display: flex;
gap: 10px;
width: 300px;
border: 2px dashed #b4bfcb;
}
.texto {
flex: 1;
overflow-wrap: anywhere;
}Aquí está bien: la dirección se parte y cabe en la fila. Pero si quitas overflow-wrap: anywhere (pruébalo en el editor), la dirección sale de la caja. Los elementos flex tienen por omisión min-width: auto: no se encogen por debajo de su contenido más largo, y una palabra o una URL sin espacios es un contenido larguísimo. La solución general es min-width: 0 en el elemento flexible, más overflow-wrap: anywhere si el texto debe partirse. Es la causa número uno de las páginas que se desbordan en el celular; está explicada en las rarezas.
Grid: filas y columnas a la vez
Flexbox piensa en una dimensión: una fila o una columna, y los elementos deciden su tamaño. Grid piensa en dos: defines una rejilla de filas y columnas en el contenedor y colocas los elementos en ella. Como regla rápida: Flexbox para componentes (una barra, un botón con icono, una fila de etiquetas) y Grid para la estructura (la página, una galería, un formulario a dos columnas).
<div class="g"> <div>1</div><div>2</div><div>3</div> <div>4</div><div>5</div><div>6</div> </div>
.g {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
gap: 8px;
}
.g div {
padding: 16px;
background: #1e64af;
color: white;
font: 600 15px system-ui, sans-serif;
border-radius: 6px;
}La unidad fr (fracción) reparte el espacio libre: con 1fr 2fr 1fr la columna del medio mide el doble que las de los lados (2 veces, medido). Los elementos se colocan solos, por orden, llenando cada fila.
Columnas que se adaptan solas
La línea más famosa de Grid crea tantas columnas como quepan, cada una de al menos un ancho mínimo, sin una sola regla @media:
<div class="galeria"> <div>1</div><div>2</div><div>3</div><div>4</div> <div>5</div><div>6</div><div>7</div> </div>
.galeria {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 10px;
}
.galeria div {
aspect-ratio: 1;
display: grid;
place-items: center;
background: #1e64af;
color: white;
font: 600 20px system-ui, sans-serif;
border-radius: 8px;
}Léela de dentro hacia fuera: cada columna mide como mínimo 150 px y como máximo una fracción (minmax(150px, 1fr)), y repeat(auto-fit, …) mete tantas como quepan. En un marco de 720 píxeles de ancho salen 4 columnas; ábrelo en el editor y prueba los botones de celular y tableta. place-items: center, de paso, centra el número dentro de cada caja: es la forma más corta de centrar con Grid.
Áreas con nombre
Para la estructura de una página, Grid permite dibujar el diseño con nombres, casi como un plano:
<div class="pagina"> <header>header</header> <aside>aside</aside> <main>main</main> <footer>footer</footer> </div>
.pagina {
display: grid;
grid-template-columns: 1fr 2fr;
grid-template-areas:
"header header"
"aside main"
"footer footer";
gap: 6px;
font: 600 15px system-ui, sans-serif;
color: white;
}
header { grid-area: header; background: #00264f; }
aside { grid-area: aside; background: #33475b; }
main { grid-area: main; background: #1e64af; min-height: 80px; }
footer { grid-area: footer; background: #5b6b7c; }
.pagina > * { padding: 12px; border-radius: 6px; }Cada cadena de grid-template-areas es una fila, y cada palabra, una celda. Repetir un nombre hace que el área ocupe varias celdas. Para cambiar el diseño en el celular (todo en una columna), basta con redefinir las áreas dentro de una regla @media, sin tocar el HTML: lo harás en la lección 8.
position, lo justo
Flexbox y Grid colocan los elementos dentro del flujo de la página. A veces hace falta sacar algo de ese flujo: una etiqueta de «Nuevo» en la esquina de una tarjeta, una cabecera que se queda arriba al bajar. Para eso está position:
staticEl valor por omisión: el elemento va donde le toca.relativeVa donde le toca, pero se puede desplazar contop,left… Sobre todo sirve de referencia para sus hijos conabsolute.absoluteSale del flujo y se coloca respecto al ancestro más cercano que tengapositiondistinta destatic.fixedSe coloca respecto a la ventana y no se mueve al desplazarse.stickySe comporta como normal hasta que, al desplazarte, llega al borde indicado (top: 0) y se queda pegado mientras su contenedor siga a la vista.
<article class="tarjeta"> <span class="etiqueta">Nuevo</span> <h2>Audífonos inalámbricos</h2> <p>$1,299.00 MXN</p> </article>
.tarjeta {
position: relative;
max-width: 260px;
padding: 16px;
border: 2px solid #c9d6e4;
border-radius: 10px;
font-family: system-ui, sans-serif;
}
.etiqueta {
position: absolute;
top: -10px;
right: 12px;
padding: 2px 10px;
border-radius: 99px;
background: #1e64af;
color: white;
font-size: 13px;
}La etiqueta se coloca respecto a la tarjeta porque esta tiene position: relative. Medida en los tres navegadores, asoma 8 píxeles por encima de la tarjeta y queda a 14 de su lado derecho: los 10 y 12 píxeles de top y right se cuentan desde la cara interior del borde, que mide 2. Sin esa línea, la etiqueta se colocaría respecto a la página entera: es el olvido más común con absolute.
Cuando dos elementos posicionados se enciman, z-index decide cuál queda arriba (el número más alto). Tiene una trampa, los «contextos de apilamiento», por la que a veces un z-index: 9999 no gana a uno de 2; está en las rarezas.
Retos
Reto 1. Haz un pie de página con tres columnas de enlaces que, cuando no quepan, pasen a la línea siguiente. Usa Flexbox.
Ver la solución
<footer class="pie"> <nav><strong>Tienda</strong><a href="#">Ofertas</a><a href="#">Envíos</a></nav> <nav><strong>Ayuda</strong><a href="#">Devoluciones</a><a href="#">Contacto</a></nav> <nav><strong>Empresa</strong><a href="#">Nosotros</a><a href="#">Empleo</a></nav> </footer>
.pie {
display: flex;
flex-wrap: wrap;
gap: 24px;
padding: 16px;
background: #0f1f33;
color: white;
font-family: system-ui, sans-serif;
}
.pie nav {
display: flex;
flex-direction: column;
gap: 6px;
flex: 1 1 140px;
}
.pie a { color: #c9d6e4; }Reto 2. Haz con Grid un formulario a dos columnas: las etiquetas a la izquierda, alineadas a la derecha, y los campos a la derecha ocupando todo lo que quede.
Ver la solución
<form class="f"> <label for="n">Nombre</label><input id="n" name="nombre"> <label for="c">Correo electrónico</label><input id="c" name="correo" type="email"> <label for="t">Teléfono</label><input id="t" name="tel" type="tel"> </form>
.f {
display: grid;
grid-template-columns: max-content 1fr;
gap: 10px 12px;
align-items: center;
font-family: system-ui, sans-serif;
}
.f label { text-align: right; }
.f input { font: inherit; padding: 6px; }max-content hace que la primera columna mida exactamente lo que la etiqueta más larga, y 1fr le da el resto a los campos. Las etiquetas y los campos se colocan solos, alternando, porque Grid llena celda a celda.
Reto 3. ¿Qué hace cada línea? display: grid; place-items: center; min-height: 100dvh; aplicada a body.
Ver la solución
Convierte la página en una rejilla de una celda que ocupa al menos todo el alto visible de la ventana (100dvh) y centra su contenido en horizontal y en vertical. Es la forma más corta de centrar una tarjeta de inicio de sesión o una página de «Próximamente».
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.
