",
- "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background-color: lavender; border: 2px dashed slategray; }",
+ "title": "Padding",
+ "description": "Every element in CSS is a box with four layers: content, padding, border, and margin. Padding creates breathing room between your content and the box's edge.
Without padding, text presses against borders awkwardly. Padding makes content readable and visually balanced.
.card {\n padding: 1rem;\n}
",
+ "task": "This profile card looks cramped. Add padding: 1rem to .card so the text has room to breathe.",
+ "previewHTML": "
",
- "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background-color: mintcream; padding: 1rem; }",
+ "title": "Borders",
+ "description": "Borders create visual boundaries around elements. The border shorthand takes three values: width, style, and color.
Common styles: solid, dashed, dotted, none",
+ "task": "Add a subtle left accent to the card with border-left: 4px solid steelblue.",
+ "previewHTML": "
Sarah Chen
Frontend Developer
",
+ "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; background: #f5f5f5; } .card { background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); padding: 1rem; } .card h3 { margin: 0 0 4px; } .card p { margin: 0; color: #666; }",
"sandboxCSS": "",
- "codePrefix": ".box {\n ",
+ "codePrefix": ".card {\n ",
"initialCode": "",
"codeSuffix": "\n}",
- "solution": "border: 2px solid darkslategray;",
+ "solution": "border-left: 4px solid steelblue;",
"previewContainer": "preview-area",
"validations": [
{
"type": "regex",
- "value": "border:\\s*2px\\s+solid\\s+darkslategray",
- "message": "Set border: 2px solid darkslategray",
+ "value": "border-left:\\s*4px\\s+solid\\s+steelblue",
+ "message": "Set border-left: 4px solid steelblue",
"options": { "caseSensitive": false }
}
]
},
{
"id": "box-model-3",
- "title": "Adding Margins",
- "description": "Margins create space between elements, controlling how they relate to one another within a layout. Unlike padding (which affects internal spacing), margins exist outside the element's border.",
- "task": "Set margin to 1rem to create space between this element and its neighbors.",
- "previewHTML": "
This box needs margins
Adjacent element
",
- "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .container { background-color: whitesmoke; padding: 8px; } .outer { background-color: plum; padding: 1rem; border: 2px solid orchid; } .neighbor { background-color: lightblue; padding: 1rem; border: 2px solid steelblue; }",
+ "title": "Margins",
+ "description": "Margins create space outside the element, separating it from neighbors. While padding pushes content inward, margins push other elements away.",
+ "task": "Add space between these two profile cards with margin-bottom: 1rem on .card.",
+ "previewHTML": "
Sarah Chen
Frontend Developer
Alex Rivera
UX Designer
",
+ "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; background: #f5f5f5; } .card { background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); padding: 1rem; border-left: 4px solid steelblue; } .card h3 { margin: 0 0 4px; } .card p { margin: 0; color: #666; }",
"sandboxCSS": "",
- "codePrefix": ".outer {\n ",
+ "codePrefix": ".card {\n ",
"initialCode": "",
"codeSuffix": "\n}",
- "solution": "margin: 1rem;",
+ "solution": "margin-bottom: 1rem;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
- "value": { "property": "margin", "expected": "1rem" },
- "message": "Set margin: 1rem"
+ "value": { "property": "margin-bottom", "expected": "1rem" },
+ "message": "Set margin-bottom: 1rem"
}
]
},
{
"id": "box-model-4",
- "title": "Box Sizing: Border-Box",
- "description": "The box-sizing property determines how element dimensions are calculated. The default content-box excludes padding and border from width/height, while border-box includes them, making layout calculations more intuitive.",
- "task": "Set box-sizing to border-box so padding and border are included in the width.",
- "previewHTML": "
box-sizing: border-box includes padding and border in the width, making sizing predictable. Most developers apply this to all elements.",
+ "task": "Both cards have width: 200px. The left uses default sizing (content-box), making it wider than expected. Fix the right card with box-sizing: border-box.",
+ "previewHTML": "
Content-boxBorder-box
",
+ "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; background: #f5f5f5; } .demo { display: flex; gap: 1rem; } .card { width: 200px; padding: 1rem; border: 4px solid steelblue; background: white; border-radius: 8px; }",
"sandboxCSS": "",
- "codePrefix": ".sized {\n ",
+ "codePrefix": ".fix {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "box-sizing: border-box;",
@@ -92,87 +92,98 @@
},
{
"id": "box-model-5",
- "title": "Margin Collapse",
- "description": "When two vertical margins meet, they collapse to the larger value instead of adding up. Understanding this behavior is crucial for consistent vertical spacing.",
- "task": "Set margin-bottom to 2rem. Notice the space between paragraphs equals 2rem (not 3rem) due to margin collapse.",
- "previewHTML": "
",
- "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .padded { background-color: papayawhip; border: 2px solid orange; }",
+ "title": "Border Radius",
+ "description": "While not part of the classic box model, border-radius rounds the corners of an element's border box. Use 50% on a square element to create a circle.",
+ "task": "Make the avatar image circular with border-radius: 50%.",
+ "previewHTML": "
CSS named colors: CSS includes 147 named colors like steelblue, coral, gold, and tomato. These are easy to remember and read.
The background-color property: Sets the fill color behind an element's content and padding areas. The color extends to the edge of the element's border.
.box {\n background-color: lightblue;\n}
",
- "task": "Set background-color to lightcyan on .box.",
- "previewHTML": "
Background Demo
",
- "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { padding: 1rem; border: 2px solid steelblue; }",
+ "description": "Color is one of the most powerful tools in web design. It creates visual hierarchy, conveys meaning, and establishes brand identity. CSS provides multiple ways to specify colors.
CSS named colors: CSS includes 147 named colors like steelblue, coral, gold, and tomato. These are easy to remember and read.
The background-color property: Sets the fill color behind an element's content and padding areas.
.card {\n background-color: lightblue;\n}
",
+ "task": "This notification card needs a subtle background. Set background-color: seashell on .alert.",
+ "previewHTML": "
New message
You have 3 unread notifications
",
+ "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .alert { padding: 1rem; border-left: 4px solid coral; border-radius: 4px; } .alert strong { display: block; margin-bottom: 4px; } .alert p { margin: 0; color: #666; font-size: 0.9rem; }",
"sandboxCSS": "",
- "codePrefix": ".box {\n ",
+ "codePrefix": ".alert {\n ",
"initialCode": "",
"codeSuffix": "\n}",
+ "solution": "background-color: seashell;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
- "value": { "property": "background-color", "expected": "lightcyan" },
- "message": "Set background-color: lightcyan"
+ "value": { "property": "background-color", "expected": "seashell" },
+ "message": "Set background-color: seashell"
}
]
},
{
"id": "colors-2",
"title": "Text Color",
- "description": "The color property sets the color of text content. Good contrast between text and background is essential for readability.",
- "task": "Set color to darkslategray on .box.",
- "previewHTML": "
Color & Contrast
",
- "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { padding: 1rem; background-color: lightcyan; border: 2px solid steelblue; }",
+ "description": "The color property sets the color of text content. Good contrast between text and background is essential for readability and accessibility.",
+ "task": "Make the alert title stand out by setting color: coral on .title.",
+ "previewHTML": "
Warning
Your session will expire in 5 minutes
",
+ "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .alert { padding: 1rem; background-color: seashell; border-left: 4px solid coral; border-radius: 4px; } .alert .title { display: block; margin-bottom: 4px; } .alert p { margin: 0; color: #666; font-size: 0.9rem; }",
"sandboxCSS": "",
- "codePrefix": ".box {\n ",
+ "codePrefix": ".title {\n ",
"initialCode": "",
"codeSuffix": "\n}",
+ "solution": "color: coral;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
- "value": { "property": "color", "expected": "darkslategray" },
- "message": "Set color: darkslategray"
+ "value": { "property": "color", "expected": "coral" },
+ "message": "Set color: coral"
}
]
},
{
"id": "colors-3",
"title": "Border Color",
- "description": "Borders can have their own color using border-color, or you can specify color in the border shorthand.",
- "task": "Set border-color to coral on .box.",
- "previewHTML": "
Border Color
",
- "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { padding: 1rem; background-color: seashell; border: 4px solid gray; }",
+ "description": "Borders can have their own color using border-color. This is useful when you want to change just the color without redefining the entire border.",
+ "task": "This card needs an accent border. Set border-color: coral on .card.",
+ "previewHTML": "
width: 80%; /* relative to parent */\nmax-width: 40rem; /* relative to root font */\npadding: 16px; /* fixed pixels */
",
- "task": "Set the width of .box to 80% and max-width to 40rem.",
- "previewHTML": "
Resize me!
",
- "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .box { background: #f5f5f5; padding: 1rem; }",
+ "title": "Relative Units",
+ "description": "CSS offers two types of units: absolute (like px) and relative (like % and rem). Relative units adapt to their context, making layouts flexible and accessible.
Common relative units: • % – Relative to parent element • rem – Relative to root font size (typically 16px) • em – Relative to element's font size
A common pattern for readable content: set width: 100% so it fills available space, then max-width: 40rem to cap line length for readability.",
+ "task": "This article text runs too wide on large screens. Add max-width: 40rem to .article for optimal reading width.",
+ "previewHTML": "
The Art of Typography
Good typography is invisible. When text is set well, readers absorb information without noticing the design decisions that make it comfortable to read. Line length is crucial—too wide and eyes get lost, too narrow and reading becomes choppy.
The ideal line length is 45-75 characters per line. At typical font sizes, this works out to roughly 40rem maximum width.
",
- "task": "Set the width of .sized to calc(100% - 2rem) and min-height to calc(10vh + 1rem).",
- "previewHTML": "
Calc Demo
",
- "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .sized { background: #e8f5e9; padding: 1rem; }",
+ "title": "calc() Function",
+ "description": "The calc() function lets you mix different units in calculations. This is essential for layouts that combine fixed and flexible sizing, like a sidebar layout.",
+ "task": "The main content should fill the remaining space after the 200px sidebar. Set width: calc(100% - 200px) on .main.",
+ "previewHTML": "
Main Content
This area should fill the remaining width after accounting for the fixed-width sidebar.
width: 50vw; /* 50% of viewport width */\nheight: 20vh; /* 20% of viewport height */
",
- "task": "Give .view a width of 50vw and height of 20vh.",
- "previewHTML": "
Viewport Box
",
- "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .view { background: #ffe0b2; }",
+ "title": "Viewport Units",
+ "description": "Viewport units size elements relative to the browser window: • vw – 1% of viewport width • vh – 1% of viewport height
These are perfect for full-screen sections like hero banners.",
+ "task": "Make this hero section fill the viewport height by setting min-height: 100vh on .hero.",
+ "previewHTML": "
",
- "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .cards > div { background: #d1c4e9; padding: 1rem; }",
+ "description": "Combine CSS Grid with auto-fit or auto-fill for responsive column layouts that automatically adjust the number of columns based on available space.",
+ "task": "Add display: grid, grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)), and gap: 1rem to .features.",
+ "previewHTML": "
How it works: When you set display: flex on an element, it becomes a flex container. Its direct children automatically become flex items that flow along a main axis (horizontal by default). This single property transforms stacked block elements into a horizontal row.
The two axes: • Main axis – The primary direction items flow (row = left→right) • Cross axis – Perpendicular to main (row = top→bottom)
.container {\n display: flex;\n /* Items now flow horizontally */\n}
",
- "task": "Add display: flex to .wrap to arrange the boxes horizontally.",
- "previewHTML": "
1
2
3
",
- "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background: steelblue; color: white; padding: 1rem; margin: 8px; text-align: center; font-weight: bold; }",
- "sandboxCSS": ".wrap { border: 2px dashed #aaa; padding: 1rem; }",
- "codePrefix": ".wrap {\n ",
+ "description": "Before flexbox, creating even simple layouts required floats, positioning hacks, or table-based layouts. Flexbox (Flexible Box Layout) revolutionized CSS by providing a one-dimensional layout system designed specifically for distributing space and aligning content.
How it works: When you set display: flex on an element, it becomes a flex container. Its direct children automatically become flex items that flow along a main axis (horizontal by default). This single property transforms stacked block elements into a horizontal row.
The two axes: • Main axis – The primary direction items flow (row = left→right) • Cross axis – Perpendicular to main (row = top→bottom)
",
- "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background: steelblue; color: white; padding: 1rem; margin: 8px; text-align: center; font-weight: bold; width: 3rem; height: 3rem; display: flex; align-items: center; justify-content: center; } .middle { background: mediumseagreen; }",
- "sandboxCSS": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 12rem; align-items: center; }",
- "codePrefix": ".middle {\n ",
+ "title": "Flex Grow",
+ "description": "The flex property on items controls how they grow and shrink. flex: 1 makes an item grow to fill available space. Multiple items with flex: 1 share space equally.",
+ "task": "Make the search input expand to fill available space by setting flex: 1 on .search.",
+ "previewHTML": "",
+ "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .toolbar { display: flex; gap: 8px; padding: 1rem; background: #f5f5f5; border-radius: 8px; } .search { padding: 8px 1rem; border: 1px solid #ddd; border-radius: 4px; font-size: 1rem; } .btn { padding: 8px 1rem; background: steelblue; color: white; border: none; border-radius: 4px; cursor: pointer; }",
+ "sandboxCSS": "",
+ "codePrefix": ".search {\n ",
"initialCode": "",
"codeSuffix": "\n}",
- "solution": "align-self: flex-start;",
+ "solution": "flex: 1;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
- "value": {
- "property": "align-self",
- "expected": "flex-start"
- },
- "message": "Set align-self: flex-start"
+ "value": { "property": "flex", "expected": "1" },
+ "message": "Set flex: 1"
}
]
}
diff --git a/lessons/grid.json b/lessons/grid.json
index eb40907..fcc141c 100644
--- a/lessons/grid.json
+++ b/lessons/grid.json
@@ -8,253 +8,148 @@
{
"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.
How it works: Set display: grid on a container. Then define your column structure with grid-template-columns. The fr unit represents a fraction of available space.
",
- "task": "Add display: grid, grid-template-columns: repeat(3, 1fr), and gap: 1rem to .grid.",
- "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",
+ "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