Library / Frontend
Build a Responsive CSS Grid Dashboard Layout
This lesson teaches advanced learners how to construct a robust and responsive dashboard layout using modern CSS Grid features, covering explicit grid definition, adaptive behavior, and nested grid patterns.
Want your own version of this lesson, tailored to your level?
⑂ Generate my versionWhat this lesson teaches, step by step
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Grid Dashboard</title><link rel="stylesheet" href="style.css"></head><body><div class="dashboard-container"><header class="header"><h1>Dashboard Title</h1></header><nav class="sidebar"><ul><li><a href="#">Overview</a></li><li><a href="#">Analytics</a></li><li><a href="#">Settings</a></li></ul></nav><main class="main-content"><div class="widget"><h3>Widget 1</h3><p>Data visualization here.</p></div><div class="widget"><h3>Widget 2</h3><p>Key performance indicators.</p></div><div class="widget"><h3>Widget 3</h3><p>Recent activity feed.</p></div><div class="widget"><h3>Widget 4</h3><p>User preferences.</p></div><div class="widget"><h3>Widget 5</h3><p>Another data point.</p></div><div class="widget"><h3>Widget 6</h3><p>System status.</p></div></main><footer class="footer"><p>© 2023 Grid Dashboard</p></footer></div></body></html>
We begin by setting up a semantic HTML structure. The `.dashboard-container` will serve as our primary grid container, enclosing distinct areas like the header, sidebar, main content, and footer. Within the `main-content`, we've added several `.widget` divs, which will later become individual grid items, demonstrating how nested grids can manage complex layouts effectively. This foundational markup is crucial for defining our grid areas.
body {margin: 0;font-family: sans-serif;}.dashboard-container {display: grid;grid-template-columns: 250px 1fr;grid-template-rows: auto 1fr auto;grid-template-areas:"header header""sidebar main""footer footer";min-height: 100vh;}.header {grid-area: header;background-color: #34495e;color: white;padding: 1rem;}.sidebar {grid-area: sidebar;background-color: #2c3e50;color: white;padding: 1rem;}.sidebar ul {list-style: none;padding: 0;}.sidebar li {margin-bottom: 0.5rem;}.sidebar a {color: white;text-decoration: none;}.main-content {grid-area: main;background-color: #ecf0f1;padding: 1.5rem;display: grid;grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));gap: 1.5rem;}.footer {grid-area: footer;background-color: #34495e;color: white;padding: 1rem;text-align: center;}Here, we apply `display: grid` to the `.dashboard-container` and define its overall structure. `grid-template-columns` sets a fixed-width sidebar (250px) and a flexible main area (1fr). `grid-template-rows` defines the header and footer as `auto` (content-sized) and the main section as `1fr` (taking remaining space). Crucially, `grid-template-areas` uses named areas for clarity, mapping `header`, `sidebar`, `main`, and `footer` directly to our HTML elements. Notice also that the `.main-content` itself is now a grid container, preparing for nested widget layouts.
@media (max-width: 768px) {.dashboard-container {grid-template-columns: 1fr;grid-template-rows: auto auto 1fr auto;grid-template-areas:"header""sidebar""main""footer";}.sidebar {padding-bottom: 0.5rem;}.sidebar ul {display: flex;justify-content: space-around;}.sidebar li {margin-bottom: 0;}.main-content {padding: 1rem;gap: 1rem;grid-template-columns: 1fr;}}Responsiveness is key for dashboards. We introduce a media query to redefine our grid for smaller screens. Below 768px, the layout collapses into a single column using `grid-template-columns: 1fr;`. The `grid-template-areas` are reordered to stack the header, sidebar, main content, and footer vertically. The sidebar's list items are also converted to a flexbox layout to display horizontally, making better use of limited horizontal space. This demonstrates how grid definitions can be dynamically adjusted for different viewports.
.widget {background-color: white;border-radius: 8px;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);padding: 1.5rem;}.main-content {grid-auto-flow: dense;}.widget:nth-child(1) {grid-column: span 2;}.widget:nth-child(4) {grid-row: span 2;}Our `.main-content` is already a grid container, so now we focus on its children, the `.widget` elements. We define a flexible widget layout using `grid-template-columns: repeat(auto-fit, minmax(300px, 1fr))` which creates as many 300px-wide columns as possible, stretching to fill the remaining space. `grid-auto-flow: dense` allows the grid algorithm to backfill empty spaces with smaller items, optimizing the packing. We then explicitly make the first widget span two columns and the fourth widget span two rows, showcasing how individual grid items can occupy multiple tracks for varied visual emphasis.