{ "$schema": "../schemas/code-crispies-module-schema.json", "id": "grid", "title": "Grid", "description": "Master the grid layout system for complex two-dimensional layouts", "difficulty": "intermediate", "lessons": [ { "id": "grid-1", "title": "Grid Container Basics", "description": "Learn how to create a grid container and define basic grid structures.

.container {\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  gap: 1rem;\n}
", "task": "Create a .grid with display: grid, grid-template-columns: repeat(3, 1fr), and gap: 1rem.", "previewHTML": "
1
2
3
4
5
6
", "previewBaseCSS": "body { font-family: system-ui, -apple-system, sans-serif; padding: 1.25rem; } .item { background-color: #9b59b6; color: white; padding: 1.25rem; text-align: center; font-weight: bold; }", "sandboxCSS": ".grid { border: 0.125rem dashed #ccc; padding: 1rem; }", "codePrefix": "/* Create a grid with 3 equal columns and gap */\n", "initialCode": "", "codeSuffix": "", "solution": ".grid {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 1rem;\n}", "previewContainer": "preview-area", "concept": { "explanation": "CSS Grid is a 2D layout system that divides space into rows and columns, called tracks. Unlike Flexbox which flows in one direction, Grid controls both axes simultaneously. The 1fr unit creates flexible tracks that share available space equally, while gap adds spacing between grid cells without affecting the outer edges.", "diagram": "Grid with 3 columns (tracks)\n\n┌───────────────────────────────┐\n│ GRID CONTAINER │\n│ ┌───┐ ┌───┐ ┌───┐ │\n│ │ 1 │ │ 2 │ │ 3 │ Row 1 │\n│ └───┘ └───┘ └───┘ │\n│ ↑ ↑ ↑ │\n│ 1fr 1fr 1fr (equal) │\n│ ┌───┐ ┌───┐ ┌───┐ │\n│ │ 4 │ │ 5 │ │ 6 │ Row 2 │\n│ └───┘ └───┘ └───┘ │\n│ ← gap between cells → │\n└───────────────────────────────┘", "containerVsItem": "display: grid, grid-template-columns, and gap are all CONTAINER properties. The parent defines the grid structure and spacing, while children automatically flow into grid cells." }, "validations": [ { "type": "contains", "value": ".grid", "message": "Use the .grid class selector", "options": { "caseSensitive": false } }, { "type": "property_value", "value": { "property": "display", "expected": "grid" }, "message": "Set display: grid", "options": { "exact": true } }, { "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 } }, { "type": "property_value", "value": { "property": "gap", "expected": "1rem" }, "message": "Set gap: 1rem", "options": { "exact": true } } ] }, { "id": "grid-2", "title": "Grid Template Areas", "description": "Use named grid areas to create visual layouts that are easy to understand.", "task": "Add grid-template-areas to create a layout with header spanning full width, sidebar and content in middle, and footer spanning full width.", "previewHTML": "
Header
Main Content
", "previewBaseCSS": "body { font-family: system-ui, -apple-system, sans-serif; padding: 1.25rem; } .page > div { padding: 1.25rem; color: white; text-align: center; font-weight: bold; } .header { background-color: #e74c3c; } .sidebar { background-color: #3498db; } .content { background-color: #2ecc71; } .footer { background-color: #f39c12; }", "sandboxCSS": ".page { border: 0.125rem dashed #ccc; padding: 1rem; height: 25rem; }", "codePrefix": "/* Create a layout using grid-template-areas */\n.page {\n display: grid;\n grid-template-columns: 12rem 1fr;\n grid-template-rows: auto 1fr auto;\n gap: 1rem;\n \n /* Add your grid-template-areas code below */\n", "initialCode": "", "codeSuffix": "\n}\n\n/* Define which element goes in which grid area */\n.header {\n grid-area: header;\n}\n\n.sidebar {\n grid-area: sidebar;\n}\n\n.content {\n grid-area: content;\n}\n\n.footer {\n grid-area: footer;\n}", "solution": "grid-template-areas:\n \"header header\"\n \"sidebar content\"\n \"footer footer\";", "previewContainer": "preview-area", "concept": { "explanation": "Grid template areas let you create visual ASCII-art layouts that mirror your design. Each string represents a row, and each name represents a column. When the same name appears multiple times in a row or column, that element spans across those cells. This makes complex layouts readable and maintainable.", "diagram": "grid-template-areas layout\n\n┌─────────────────────────┐\n│ \"header header\" │\n│ ┌─────────────────────┐ │\n│ │ Header │ │\n│ └─────────────────────┘ │\n│ │\n│ \"sidebar content\" │\n│ ┌──────┐ ┌────────────┐│\n│ │Side- │ │ Main ││\n│ │ bar │ │ Content ││\n│ └──────┘ └────────────┘│\n│ │\n│ \"footer footer\" │\n│ ┌─────────────────────┐ │\n│ │ Footer │ │\n│ └─────────────────────┘ │\n└─────────────────────────┘", "containerVsItem": "grid-template-areas is a CONTAINER property that defines named regions. Items use grid-area (an ITEM property) to assign themselves to those regions." }, "validations": [ { "type": "contains", "value": "grid-template-areas", "message": "Use the grid-template-areas property", "options": { "caseSensitive": false } }, { "type": "regex", "value": "grid-template-areas:\\s*['\"]header\\s+header['\"]\\s*['\"]sidebar\\s+content['\"]\\s*['\"]footer\\s+footer['\"]", "message": "Create areas: \"header header\" \"sidebar content\" \"footer footer\"", "options": { "caseSensitive": false } } ] }, { "id": "grid-3", "title": "Spanning Grid Cells", "description": "Make grid items span multiple grid cells horizontally or vertically.", "task": "Add grid-column: span 2 and grid-row: span 2 to .featured to span 2x2 cells.", "previewHTML": "
1
2
4
5
6
7
8
9
", "previewBaseCSS": "body { font-family: system-ui, -apple-system, sans-serif; padding: 1.25rem; } .item { background-color: #9b59b6; color: white; padding: 1.25rem; text-align: center; font-weight: bold; } .featured { background-color: #e74c3c; }", "sandboxCSS": ".grid { border: 0.125rem dashed #ccc; padding: 1rem; display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }", "codePrefix": "/* Make the featured item span 2x2 cells */\n", "initialCode": "", "codeSuffix": "", "solution": ".featured {\n grid-column: span 2;\n grid-row: span 2;\n}", "previewContainer": "preview-area", "concept": { "explanation": "Grid items can span across multiple cells using grid-column and grid-row with the span keyword. This lets individual items occupy more than one grid track in either direction. The grid automatically adjusts remaining items around the spanning element, flowing them into available cells.", "diagram": "Grid with spanning item\n\n┌─────────────────────────┐\n│ ┌───┐ ┌───┐ │\n│ │ 1 │ │ 2 │ │\n│ └───┘ └───┘ │\n│ ┌─────────┐ ┌───┐ │\n│ │Featured │ │ 4 │ │\n│ │ (2x2) │ └───┘ │\n│ │ span 2 │ ┌───┐ │\n│ │ cols & │ │ 5 │ │\n│ │ rows │ └───┘ │\n│ └─────────┘ │\n│ ┌───┐ ┌───┐ ┌───┐ │\n│ │ 6 │ │ 7 │ │ 8 │ │\n│ └───┘ └───┘ └───┘ │\n└─────────────────────────┘", "containerVsItem": "grid-column and grid-row are ITEM properties. Individual children control their own spanning behavior, while the container just defines the grid structure." }, "validations": [ { "type": "contains", "value": ".featured", "message": "Use the .featured class selector", "options": { "caseSensitive": false } }, { "type": "regex", "value": "grid-column:\\s*span\\s+2", "message": "Set grid-column: span 2", "options": { "caseSensitive": false } }, { "type": "regex", "value": "grid-row:\\s*span\\s+2", "message": "Set grid-row: span 2", "options": { "caseSensitive": false } } ] }, { "id": "grid-4", "title": "Automatic Grid Placement", "description": "Learn how to use auto-placement and auto-fit/auto-fill for responsive grid layouts.", "task": "Add display: grid and grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)) to .cards.", "previewHTML": "
Card 1
Card 2
Card 3
Card 4
Card 5
Card 6
", "previewBaseCSS": "body { font-family: system-ui, -apple-system, sans-serif; padding: 1.25rem; } .card { background-color: #3498db; color: white; padding: 1.25rem; text-align: center; font-weight: bold; height: 6rem; display: flex; align-items: center; justify-content: center; }", "sandboxCSS": ".cards { border: 0.125rem dashed #ccc; padding: 1rem; }", "codePrefix": "/* Create a responsive grid with auto-fit columns */\n", "initialCode": "", "codeSuffix": "", "solution": ".cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));\n}", "previewContainer": "preview-area", "concept": { "explanation": "auto-fit with minmax creates responsive grids that automatically adapt to available space without media queries. minmax(10rem, 1fr) sets a minimum column width of 10rem and maximum of 1fr, while auto-fit creates as many columns as will fit. When there's extra space, columns expand to fill it. This creates truly fluid layouts.", "diagram": "auto-fit responsive behavior\n\nWide viewport:\n┌──────────────────────────────┐\n│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │\n│ │ C1 │ │ C2 │ │ C3 │ │ C4 │ │\n│ └────┘ └────┘ └────┘ └────┘ │\n│ ┌────┐ ┌────┐ │\n│ │ C5 │ │ C6 │ (expands) │\n│ └────┘ └────┘ │\n└──────────────────────────────┘\n\nNarrow viewport:\n┌──────────┐\n│ ┌──────┐ │\n│ │ C1 │ │\n│ └──────┘ │\n│ ┌──────┐ │\n│ │ C2 │ │ (fewer cols)\n│ └──────┘ │\n└──────────┘", "containerVsItem": "grid-template-columns with auto-fit is a CONTAINER property. The container automatically calculates how many columns fit, and children flow into those columns without needing individual sizing." }, "validations": [ { "type": "contains", "value": ".cards", "message": "Use the .cards class selector", "options": { "caseSensitive": false } }, { "type": "property_value", "value": { "property": "display", "expected": "grid" }, "message": "Set display: grid", "options": { "exact": true } }, { "type": "regex", "value": "grid-template-columns:\\s*repeat\\(\\s*auto-fit\\s*,\\s*minmax\\(\\s*10rem\\s*,\\s*1fr\\s*\\)\\s*\\)", "message": "Set grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr))", "options": { "caseSensitive": false } } ] }, { "id": "grid-5", "title": "Grid Alignment", "description": "Control the alignment of grid items within their cells on both axes.", "task": "Add justify-items: center and align-items: center to center items within their cells.", "previewHTML": "
1
2
3
4
5
6
", "previewBaseCSS": "body { font-family: system-ui, -apple-system, sans-serif; padding: 1.25rem; } .item { background-color: #9b59b6; color: white; padding: 1.25rem; text-align: center; font-weight: bold; width: 3rem; height: 3rem; } .tall { height: 6rem; } .wide { width: 6rem; }", "sandboxCSS": ".cells { border: 0.125rem dashed #ccc; padding: 1rem; display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; height: 25rem; }", "codePrefix": "/* Center grid items both horizontally and vertically */\n.cells {\n /* Add alignment properties below */\n", "initialCode": "", "codeSuffix": "\n}", "solution": "justify-items: center;\n align-items: center;", "previewContainer": "preview-area", "concept": { "explanation": "Grid alignment works on two axes: justify-items controls horizontal positioning (inline axis), while align-items controls vertical positioning (block axis). These are CONTAINER properties that set the default alignment for all items within their assigned grid cells. Items can override this with justify-self and align-self.", "diagram": "Grid item alignment\n\n┌─────────┬─────────┬─────────┐\n│ │ │ │\n│ ┌─┐ │ ┌─┐ │ ┌─┐ │\n│ │1│ │ │2│ │ │3│ │ ← centered\n│ └─┘ │ │ │ │ └─┘ │ in cells\n│ │ └─┘ │ │\n├─────────┼─────────┼─────────┤\n│ │ │ │\n│ ┌─┐ │ ┌─┐ │ ┌───┐ │\n│ │4│ │ │5│ │ │ 6 │ │\n│ └─┘ │ └─┘ │ └───┘ │\n│ │ │ │\n└─────────┴─────────┴─────────┘\n ↑ ↑\n justify-items align-items\n (horizontal) (vertical)", "containerVsItem": "justify-items and align-items are CONTAINER properties that set default alignment for all children. Individual items can use justify-self and align-self (ITEM properties) to override." }, "validations": [ { "type": "property_value", "value": { "property": "justify-items", "expected": "center" }, "message": "Set justify-items: center", "options": { "exact": true } }, { "type": "property_value", "value": { "property": "align-items", "expected": "center" }, "message": "Set align-items: center", "options": { "exact": true } } ] }, { "id": "grid-6", "title": "Overlapping Grid Items", "description": "Learn how to create overlapping layouts by using grid positioning and z-index.", "task": "Add grid-column: 1, grid-row: 1, and z-index: 1 to .overlay to position it above the base.", "previewHTML": "
Base Content
Overlay
", "previewBaseCSS": "body { font-family: system-ui, -apple-system, sans-serif; padding: 1.25rem; } .stack { position: relative; height: 15rem; } .base { background-color: #3498db; color: white; padding: 1.25rem; display: flex; align-items: center; justify-content: center; font-weight: bold; } .overlay { background-color: rgba(231, 76, 60, 0.7); color: white; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 1.5rem; }", "sandboxCSS": ".stack { border: 0.125rem dashed #ccc; padding: 1rem; display: grid; grid-template-columns: 1fr; grid-template-rows: 1fr; }", "codePrefix": "/* Position the overlay to cover the entire grid */\n.base {\n grid-column: 1;\n grid-row: 1;\n}\n\n.overlay {\n /* Add your code below to position the overlay */\n", "initialCode": "", "codeSuffix": "\n}", "solution": "grid-column: 1;\n grid-row: 1;\n z-index: 1;", "previewContainer": "preview-area", "concept": { "explanation": "Unlike Flexbox's single-direction flow, Grid's 2D system allows multiple items to occupy the same grid cell by explicitly positioning them with grid-column and grid-row. When items overlap, z-index controls stacking order - higher values appear on top. This enables layered designs like image overlays, card effects, and complex compositions.", "diagram": "Overlapping grid items\n\n┌─────────────────────────┐\n│ Grid Cell (1, 1) │\n│ │\n│ ┌──────────────────┐ │\n│ │ Base (z-index:0) │ │\n│ │ ┌────────────┐ │ │\n│ │ │ Overlay │ │ │\n│ └──┤ (z-index:1)├──┘ │\n│ │ (on top) │ │\n│ └────────────┘ │\n│ │\n│ Both items positioned │\n│ at grid-column: 1, │\n│ grid-row: 1 │\n└─────────────────────────┘", "containerVsItem": "grid-column, grid-row, and z-index are all ITEM properties. Individual children control their own grid placement and stacking order independently." }, "validations": [ { "type": "property_value", "value": { "property": "grid-column", "expected": "1" }, "message": "Set grid-column: 1", "options": { "exact": true } }, { "type": "property_value", "value": { "property": "grid-row", "expected": "1" }, "message": "Set grid-row: 1", "options": { "exact": true } }, { "type": "regex", "value": "z-index:\\s*[1-9]\\d*", "message": "Set z-index to a positive number", "options": { "caseSensitive": false } } ] } ] }