{ "$schema": "../schemas/code-crispies-module-schema.json", "id": "grid", "title": "CSS Grid", "description": "Master the grid layout system for complex two-dimensional layouts", "difficulty": "intermediate", "lessons": [ { "id": "grid-1", "title": "Grid Container", "description": "CSS Grid is a two-dimensional layout system, meaning it can handle both columns AND rows simultaneously. While Flexbox excels at one-dimensional layouts (a single row or column), Grid shines when you need precise control over both dimensions—like photo galleries, dashboards, or page layouts.

How it works: Set display: grid on a container, then define columns with grid-template-columns. The fr unit represents a fraction of available space—1fr 1fr 1fr creates three equal columns.

Key properties:
grid-template-columns – Defines column sizes
repeat(3, 1fr) – Shorthand for 3 equal columns
gap – Adds spacing between grid cells

.gallery {\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  gap: 1rem;\n}
", "task": "This photo gallery displays images in a single column. Add display: grid to .gallery to enable grid layout.", "previewHTML": "
\"Mountains\"
Mountain View
\"Beach\"
Sunny Beach
\"City\"
City Skyline
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; background: #f5f5f5; } .photo { margin: 0; background: white; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .photo img { width: 100%; display: block; } .photo figcaption { padding: 8px; text-align: center; font-size: 0.9rem; color: #666; }", "sandboxCSS": "", "codePrefix": ".gallery {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "display: grid;", "previewContainer": "preview-area", "validations": [ { "type": "property_value", "value": { "property": "display", "expected": "grid" }, "message": "Set display: grid" } ] }, { "id": "grid-2", "title": "Grid Columns", "description": "The grid-template-columns property defines how many columns your grid has and how wide each one should be. The fr unit divides available space into fractions—1fr 1fr 1fr creates three equal columns.", "task": "Add grid-template-columns: repeat(3, 1fr) to display the photos in three equal columns.", "previewHTML": "
\"Mountains\"
Mountain View
\"Beach\"
Sunny Beach
\"City\"
City Skyline
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; background: #f5f5f5; } .gallery { display: grid; } .photo { margin: 0; background: white; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .photo img { width: 100%; display: block; } .photo figcaption { padding: 8px; text-align: center; font-size: 0.9rem; color: #666; }", "sandboxCSS": "", "codePrefix": ".gallery {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "grid-template-columns: repeat(3, 1fr);", "previewContainer": "preview-area", "validations": [ { "type": "regex", "value": "grid-template-columns:\\s*repeat\\(\\s*3\\s*,\\s*1fr\\s*\\)", "message": "Set grid-template-columns: repeat(3, 1fr)", "options": { "caseSensitive": false } } ] }, { "id": "grid-3", "title": "Grid Gap", "description": "Just like in Flexbox, the gap property adds consistent spacing between grid cells. It creates gutters between columns and rows without adding space around the edges.", "task": "Add gap: 1rem to create breathing room between the photos.", "previewHTML": "
\"Mountains\"
Mountain View
\"Beach\"
Sunny Beach
\"City\"
City Skyline
\"Tree\"
Lone Tree
\"Sunset\"
Golden Sunset
\"Clouds\"
Cloudy Sky
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; background: #f5f5f5; } .gallery { display: grid; grid-template-columns: repeat(3, 1fr); } .photo { margin: 0; background: white; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .photo img { width: 100%; display: block; } .photo figcaption { padding: 8px; text-align: center; font-size: 0.9rem; color: #666; }", "sandboxCSS": "", "codePrefix": ".gallery {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "gap: 1rem;", "previewContainer": "preview-area", "validations": [ { "type": "property_value", "value": { "property": "gap", "expected": "1rem" }, "message": "Set gap: 1rem" } ] }, { "id": "grid-4", "title": "Spanning Columns", "description": "Grid items can span multiple columns using grid-column: span N. This is perfect for featured content that needs more visual prominence, like a hero image in a gallery.", "task": "Make the featured photo span two columns by adding grid-column: span 2 to .featured.", "previewHTML": "
FEATURED%3C/svg%3E\" alt=\"Featured\">
Featured Landscape
\"Beach\"
Beach
\"City\"
City
\"Tree\"
Tree
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; background: #f5f5f5; } .gallery { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; } .photo { margin: 0; background: white; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .photo img { width: 100%; display: block; } .photo figcaption { padding: 8px; text-align: center; font-size: 0.9rem; color: #666; }", "sandboxCSS": "", "codePrefix": ".featured {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "grid-column: span 2;", "previewContainer": "preview-area", "validations": [ { "type": "regex", "value": "grid-column:\\s*span\\s+2", "message": "Set grid-column: span 2", "options": { "caseSensitive": false } } ] }, { "id": "grid-5", "title": "Auto-Fit Columns", "description": "For truly responsive grids, use auto-fit with minmax(). This automatically creates as many columns as will fit, with each being at least a minimum width but growing to fill space.", "task": "Add grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)) to make the product grid responsive.", "previewHTML": "

Wireless Headphones

$79

Smart Watch

$199

Portable Speaker

$49

USB-C Hub

$35

Webcam HD

$89

Keyboard

$129

", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; background: #f5f5f5; } .products { display: grid; gap: 1rem; } .product { background: white; border-radius: 8px; padding: 1rem; box-shadow: 0 2px 4px rgba(0,0,0,0.1); text-align: center; } .product .img { height: 80px; border-radius: 4px; margin-bottom: 8px; } .product h3 { margin: 0 0 4px; font-size: 0.95rem; } .product p { margin: 0; color: steelblue; font-weight: bold; }", "sandboxCSS": "", "codePrefix": ".products {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));", "previewContainer": "preview-area", "validations": [ { "type": "regex", "value": "grid-template-columns:\\s*repeat\\(\\s*auto-fit\\s*,\\s*minmax\\(\\s*150px\\s*,\\s*1fr\\s*\\)\\s*\\)", "message": "Set grid-template-columns: repeat(auto-fit, minmax(150px, 1fr))", "options": { "caseSensitive": false } } ] }, { "id": "grid-6", "title": "Grid Template Areas", "description": "For complex page layouts, grid-template-areas lets you name regions and place items visually. It's like drawing your layout with ASCII art—incredibly readable and maintainable.", "task": "Complete the dashboard layout by adding the grid-template-areas. The header should span full width, then nav and main side by side, then footer spanning full width.", "previewHTML": "
Dashboard Header
Main Content Area
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; background: #f5f5f5; } .dashboard { display: grid; grid-template-columns: 180px 1fr; grid-template-rows: auto 1fr auto; gap: 1rem; min-height: 300px; } .header { grid-area: header; background: #1a1a2e; color: white; padding: 1rem; border-radius: 8px; } .nav { grid-area: nav; background: steelblue; color: white; padding: 1rem; border-radius: 8px; } .main { grid-area: main; background: white; padding: 1rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .footer { grid-area: footer; background: #333; color: white; padding: 1rem; border-radius: 8px; text-align: center; }", "sandboxCSS": "", "codePrefix": ".dashboard {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "grid-template-areas:\n \"header header\"\n \"nav main\"\n \"footer footer\";", "previewContainer": "preview-area", "validations": [ { "type": "contains", "value": "grid-template-areas", "message": "Use the grid-template-areas property", "options": { "caseSensitive": false } }, { "type": "regex", "value": "['\"]header\\s+header['\"]", "message": "Header should span both columns: \"header header\"", "options": { "caseSensitive": false } }, { "type": "regex", "value": "['\"]nav\\s+main['\"]", "message": "Nav and main should be side by side: \"nav main\"", "options": { "caseSensitive": false } }, { "type": "regex", "value": "['\"]footer\\s+footer['\"]", "message": "Footer should span both columns: \"footer footer\"", "options": { "caseSensitive": false } } ] } ] }