Referencia Detallada de CSS Grid y Flexbox
modern CSS layout con Grid y Flexbox. Cubre grid templates, areas, subgrid, responsive layouts, flexbox alignment, wrapping, gap, container queries y cuando usar Grid vs Flexbox con ejemplos practicos y patterns.
Nota para desarrolladores hispanohablantes: Esta guía incluye ejemplos y convenciones de nomenclatura adaptadas a equipos que trabajan en español. Cuando existen diferencias significativas en terminología técnica entre el inglés y el español, se indican explícitamente para facilitar la comunicación en equipos multiculturales.
Introducción
CSS Grid y Flexbox son los dos layout systems que reemplazaron floats, tables, y positioning hacks. Grid handlea two-dimensional layouts (rows y columns). Flexbox handlea one-dimensional layouts (ya sea rows o columns). Lo siguiente es una guia practica para ambos con practical patterns.
Cuando usar Grid vs Flexbox
- For alternatives, see Complete Guide to Mobile Responsive Design.
Usa CSS Grid cuando:
- Necesitas tanto rows como columns (2D layout)
- El layout tiene un defined structure
- Necesitas alinear items en ambas direcciones
- Queres gap entre items sin margins
- Necesitas areas con named regions
Usa Flexbox cuando:
- Necesitas un single row o column (1D layout)
- Items deberian grow o shrink basado en content
- Necesitas alinear items along un axis
- Necesitas reorder items sin cambiar HTML
- Necesitas dynamic spacing entre items
Rule of thumb:
Grid = page layout, card grids, dashboards
Flexbox = navigation bars, toolbars, card content, button groups
CSS Grid
Basic Grid
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
/* Responsive sin media queries */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
}
/* Fixed sidebar + fluid content */
.layout {
display: grid;
grid-template-columns: 250px 1fr;
min-height: 100vh;
}
Grid Template Areas
.page-layout {
display: grid;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
gap: 1rem;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
/* Responsive: stack en mobile */
@media (max-width: 768px) {
.page-layout {
grid-template-areas:
"header"
"main"
"sidebar"
"aside"
"footer";
grid-template-columns: 1fr;
}
}
<div class="page-layout">
<header class="header">Header</header>
<nav class="sidebar">Sidebar</nav>
<main class="main">Main content</main>
<aside class="aside">Aside</aside>
<footer class="footer">Footer</footer>
</div>
Subgrid
/* Subgrid lets children inherit parent grid tracks */
.card-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 3; /* Span 3 rows del parent grid */
}
/* Example: aligned card titles y prices */
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
}
.product-card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 3;
gap: 0;
}
.product-card .title { grid-row: 1; }
.product-card .image { grid-row: 2; }
.product-card .price { grid-row: 3; }
/* Todos los titles alinean across cards, todos los images alinean, todos los prices alinean */
Grid Alignment
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
/* Align items along el block (row) axis */
align-items: start | center | end | stretch;
/* Align items along el inline (column) axis */
justify-items: start | center | end | stretch;
/* Align el entire grid dentro del container */
align-content: start | center | end | space-between | space-around;
justify-content: start | center | end | space-between | space-around;
}
/* Individual item alignment */
.grid-item {
align-self: center;
justify-self: end;
}
Common Grid Patterns
/* Holy Grail Layout */
.holy-grail {
display: grid;
grid-template:
"header header header" auto
"nav main aside" 1fr
"footer footer footer" auto
/ 200px 1fr 200px;
min-height: 100vh;
}
/* Masonry-like layout (CSS Grid Masonry — experimental) */
.masonry {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry; /* Experimental */
gap: 1rem;
}
/* Center anything */
.center-anything {
display: grid;
place-items: center;
min-height: 100vh;
}
/* Sticky header + scrollable content */
.app-shell {
display: grid;
grid-template-rows: auto 1fr;
height: 100vh;
}
.app-header {
position: sticky;
top: 0;
z-index: 10;
}
.app-content {
overflow-y: auto;
}
Flexbox
Basic Flexbox
/* Horizontal navigation bar */
.navbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 0 1.5rem;
}
.nav-links {
display: flex;
gap: 1rem;
list-style: none;
}
/* Card con image, content, y action */
.card {
display: flex;
flex-direction: column;
gap: 1rem;
}
.card-image {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.card-content {
flex: 1; /* Take remaining space */
}
.card-actions {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
}
Flexbox Alignment
.flex-container {
display: flex;
/* Main axis alignment */
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
/* Cross axis alignment */
align-items: stretch | flex-start | center | flex-end | baseline;
/* Multi-line alignment (when wrapping) */
align-content: flex-start | center | flex-end | space-between | space-around;
/* Direction */
flex-direction: row | row-reverse | column | column-reverse;
/* Wrapping */
flex-wrap: nowrap | wrap | wrap-reverse;
/* Gap */
gap: 1rem;
}
/* Individual item alignment */
.flex-item {
align-self: flex-start | center | flex-end | stretch | baseline;
}
Flex Item Properties
.flex-item {
/* Grow: cuanto grow relative a other items */
flex-grow: 0; /* Default */
/* Shrink: cuanto shrink relative a other items */
flex-shrink: 1; /* Default */
/* Basis: initial size antes de growing/shrinking */
flex-basis: auto; /* Default — size basado en content */
/* Shorthand: flex: grow shrink basis */
flex: 1; /* = flex: 1 1 0% — equal distribution */
flex: 2; /* = flex: 2 1 0% — twice el space */
flex: auto; /* = flex: 1 1 auto — grow basado en content */
flex: none; /* = flex: 0 0 auto — no grow, no shrink */
/* Order: reorder sin cambiar HTML */
order: -1; /* Move al front */
order: 1; /* Move al back */
}
Common Flexbox Patterns
/* Center anything */
.center {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
}
/* Sticky footer con flex */
.page {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.page-content {
flex: 1;
}
/* Input con button */
.input-group {
display: flex;
align-items: stretch;
}
.input-group input {
flex: 1;
border-radius: 4px 0 0 4px;
}
.input-group button {
border-radius: 0 4px 4px 0;
}
/* Media object (avatar + content) */
.media {
display: flex;
align-items: flex-start;
gap: 1rem;
}
.media-image {
flex: 0 0 48px;
width: 48px;
height: 48px;
border-radius: 50%;
}
.media-body {
flex: 1;
}
/* Responsive wrap */
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.tag {
flex: 0 0 auto;
padding: 0.25rem 0.75rem;
border-radius: 9999px;
background: #e0e0e0;
}
Container Queries
/* Container queries — responsive basado en parent size, no viewport */
.card-wrapper {
container-type: inline-size;
container-name: card;
}
/* Styles apply basado en el container's width, no el viewport */
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 120px 1fr;
gap: 1rem;
}
}
@container card (max-width: 399px) {
.card {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
}
/* Container query units */
.card-title {
font-size: clamp(1rem, 5cqi, 1.5rem); /* cqi = container query inline */
}
.card-image {
width: 100%;
height: 50cqh; /* 50% del container height */
}
Responsive Design Patterns
/* Mobile-first grid */
.responsive-grid {
display: grid;
gap: 1rem;
grid-template-columns: 1fr;
}
@media (min-width: 640px) {
.responsive-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1024px) {
.responsive-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (min-width: 1280px) {
.responsive-grid {
grid-template-columns: repeat(4, 1fr);
}
}
/* Auto-fill grid — no media queries needed */
.auto-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
gap: 1.5rem;
}
/* Sidebar layout que colapsa en mobile */
.sidebar-layout {
display: grid;
grid-template-columns: 1fr;
}
@container (min-width: 768px) {
.sidebar-layout {
grid-template-columns: 240px 1fr;
}
}
Gap Property
/* Gap funciona en tanto Grid como Flexbox */
.grid-layout {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
/* row-gap: 1rem; */
/* column-gap: 0.5rem; */
}
.flex-layout {
display: flex;
gap: 1rem;
/* row-gap: 0.5rem; */
/* column-gap: 1rem; */
}
/* Multi-column gap */
.flex-wrap-layout {
display: flex;
flex-wrap: wrap;
gap: 1rem 2rem; /* row-gap column-gap */
}
Preguntas Frecuentes
¿Deberia usar Grid o Flexbox para mi layout?
Usa Grid cuando necesitas un two-dimensional layout con tanto rows como columns — page layouts, card grids, dashboards. Usa Flexbox cuando necesitas un one-dimensional layout — navigation bars, button groups, card content. Podes nestearlos: usa Grid para el page structure y Flexbox dentro de cada grid cell para el content layout. Ambos soportan gap, alignment, y responsive behavior.
¿Qué es subgrid y que browsers lo soportan?
Subgrid permite que un grid item herede el parent grid’s tracks (rows o columns). Esto enables aligned card grids donde titles, images, y prices se alinean across cards regardless de content length. Subgrid es supported en todos los modern browsers as of 2024 (Chrome 117+, Firefox 71+, Safari 16+). Usa grid-template-rows: subgrid o grid-template-columns: subgrid en un grid item.
¿Cómo diferieren container queries de media queries?
Media queries responden al viewport size — el entire browser window. Container queries responden al size de un parent container. Esto significa que un card component puede adaptar su layout basado en el space available en su parent, no el entire screen. Esto hace components truly reusable — el mismo card se ve diferente en un sidebar (narrow) vs un main content area (wide) sin media queries.
¿Cómo centro algo con CSS?
Para centering en un flex container: display: flex; align-items: center; justify-content: center;. Para centering en un grid container: display: grid; place-items: center;. Para centering un element en la page: usa grid con min-height: 100vh y place-items: center. Evita position: absolute con transforms para centering — remove el element del document flow y causa layout issues.
¿Cuál es la diferencia entre flex: 1 y flex: auto?
flex: 1 significa flex-grow: 1, flex-shrink: 1, flex-basis: 0% — todos los items comparten space equally regardless de content size. flex: auto significa flex-grow: 1, flex-shrink: 1, flex-basis: auto — items grow para fill space pero empiezan con su content size como basis. Usa flex: 1 cuando queres equal-sized items. Usa flex: auto cuando queres items que sean al menos tan wide como su content pero compartan extra space.
¿Cómo creo un responsive grid sin media queries?
Usa grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)). El auto-fill keyword crea tantas columns como fiteen. El minmax(min(100%, 280px), 1fr) setea cada column a al menos 280px (o 100% en very small screens) y at most 1fr. El min(100%, 280px) prevent overflow en screens mas narrow que 280px. Esto crea un grid que automaticamente adjusts column count basado en available space.
Recursos Relacionados
Complete Guide to React 19 Features
Master React 19 features. Covers server components, use() hook, actions, form actions, useActionState, useOptimistic, useFormStatus, ref as prop, document metadata, asset loading, and React Compiler with practical code examples.
GuideComplete Guide to Web Performance and Core Web Vitals
Optimize Core Web Vitals. Covers LCP, INP, CLS measurement and improvement, image optimization, font loading, render-blocking resources, lazy loading, caching strategies, and performance monitoring with practical code examples.
GuideComplete Guide to Bundle Size Optimization
Reduce JavaScript bundle size. Covers tree shaking, code splitting, dynamic imports, dependency analysis, module federation, lazy loading, compression, polyfill management, and bundle monitoring with practical webpack, Vite, and Rollup examples.
RecipeServer-Side Rendering
Improve performance and SEO with server-side rendering using Next.js, Nuxt, Astro, and other frameworks with hydration strategies.