Maquetación Web Dinámica / Layouts II: CSS Grid completo
Proyecto: dashboard completo con Grid + Flexbox
Primer PROYECTO del curso: más largo que un reto, más cercano a un encargo real. Vas a maquetar el dashboard de una app de métricas — el tipo de interfaz que pagan por construir — combinando TODO el arsenal de layout: grid de aplicación, grid de widgets, flexbox en los componentes y subgrid donde la alineación lo pida.
Reto
El dashboard de una app de métricas
Qué debes construir
El dashboard de "Pulso" (una app de analíticas ficticia), pantalla completa:
<div class="app">
<aside class="sidebar">
<p class="logo">◆ Pulso</p>
<nav><a class="activo" href="#">Resumen</a><a href="#">Reportes</a><a href="#">Audiencia</a><a href="#">Ajustes</a></nav>
<div class="usuario"><div class="avatar">M</div><span>Miguel</span></div>
</aside>
<header class="topbar">
<h1>Resumen</h1>
<input type="search" placeholder="Buscar..." aria-label="Buscar">
</header>
<main class="lienzo">
<section class="widget kpi"><p class="dato">12.4k</p><p class="etiqueta">Visitas hoy</p></section>
<section class="widget kpi"><p class="dato">3:42</p><p class="etiqueta">Tiempo promedio</p></section>
<section class="widget kpi"><p class="dato">68%</p><p class="etiqueta">Retención</p></section>
<section class="widget grafica"><p class="etiqueta">Visitas de la semana</p><div class="barras"><i style="height:40%"></i><i style="height:65%"></i><i style="height:50%"></i><i style="height:80%"></i><i style="height:70%"></i><i style="height:95%"></i><i style="height:60%"></i></div></section>
<section class="widget lista"><p class="etiqueta">Páginas top</p><ul><li><span>/inicio</span><span>4.2k</span></li><li><span>/precios</span><span>2.1k</span></li><li><span>/blog</span><span>1.8k</span></li></ul></section>
</main>
</div>body { font-family: system-ui; margin: 0; }
.app { display: grid; grid-template-columns: 170px 1fr; grid-template-rows: 52px 1fr; grid-template-areas: "sidebar topbar" "sidebar lienzo"; height: 410px; background: #f1f5f9; border-radius: 12px; overflow: hidden; }
.sidebar { grid-area: sidebar; background: #0f172a; color: white; display: flex; flex-direction: column; padding: 14px; gap: 14px; }
.logo { font-weight: 800; margin: 0; font-size: 15px; }
.sidebar nav { display: flex; flex-direction: column; gap: 2px; }
.sidebar a { color: #94a3b8; text-decoration: none; font-size: 13px; padding: 7px 10px; border-radius: 7px; }
.sidebar a.activo { background: #1e293b; color: white; }
.usuario { margin-top: auto; display: flex; align-items: center; gap: 8px; font-size: 13px; }
.avatar { width: 26px; height: 26px; border-radius: 50%; background: #6d28d9; display: grid; place-items: center; font-size: 12px; font-weight: 700; }
.topbar { grid-area: topbar; background: white; border-bottom: 1px solid #e2e8f0; display: flex; justify-content: space-between; align-items: center; padding: 0 16px; }
.topbar h1 { font-size: 15px; margin: 0; color: #1e293b; }
.topbar input { border: 1px solid #cbd5e1; border-radius: 8px; padding: 6px 12px; font-size: 12px; width: 160px; }
.lienzo { grid-area: lienzo; display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: minmax(80px, auto); gap: 10px; padding: 12px; overflow-y: auto; }
.widget { background: white; border: 1px solid #e2e8f0; border-radius: 10px; padding: 12px; }
.kpi .dato { font-size: 24px; font-weight: 800; margin: 0; color: #1e293b; }
.etiqueta { font-size: 11px; color: #64748b; margin: 0; }
.grafica { grid-column: span 2; display: flex; flex-direction: column; gap: 8px; }
.barras { display: flex; align-items: flex-end; gap: 6px; flex: 1; }
.barras i { flex: 1; background: linear-gradient(180deg, #7c3aed, #6d28d9); border-radius: 4px 4px 0 0; }
.lista ul { list-style: none; padding: 0; margin: 6px 0 0; }
.lista li { display: flex; justify-content: space-between; font-size: 12px; color: #334155; padding: 5px 0; border-bottom: 1px solid #f1f5f9; }Requisitos por zona:
- Esqueleto (grid de app): sidebar oscuro que atraviesa las dos filas,
topbar de altura fija, lienzo que llena el resto — con
grid-template-areasymin-height: 100dvh. - Sidebar (flex column): logo arriba, nav de 4 enlaces (el activo
resaltado), y el bloque de usuario ANCLADO ABAJO con
margin-top: auto(el primo flex del sticky footer). - Topbar (flex): título a la izquierda, búsqueda a la derecha, centrados verticalmente.
- Lienzo (grid de widgets): 3 KPIs arriba (dato grande + etiqueta — jerarquía del módulo 4), una "gráfica" de barras que ocupa 2 columnas (las barras son divs con alturas distintas y flex align-items: flex-end), y una lista de "páginas top".
overflow-y: autoen el lienzo: si los widgets crecen, scrollea el lienzo — no la página (los dashboards reales funcionan así).- Bonus subgrid: si agregas una fila de 3 tarjetas con título/dato/pie, alinéalas con subgrid.
Reglas
- El esqueleto y el lienzo con Grid; el interior de cada componente, con la herramienta que pida (casi siempre flex). Nada de position (eso es el módulo que viene).
- Paleta 60-30-10 con custom properties, sombras discretas, radius consistente — el módulo 4 también se evalúa aquí.
- Los widgets en HTML semántico:
sectioncon su etiqueta, listas reales,aside/header/mainen el esqueleto.
90:00
Cuando estés listo, arranca el reloj.
Qué sigue
Módulo 6 cerrado — y con él, las DOS herramientas de layout del CSS moderno. El módulo 7 completa el trío con la tercera pieza: el posicionamiento — capas, elementos que flotan, se pegan y persiguen. Lo que Grid y Flexbox no hacen, position lo remata.