- Added 'concept' objects to all 8 box model lessons - Each lesson includes 2-4 sentence beginner-friendly explanation - ASCII diagrams illustrate the 4-layer box model structure - Concepts cover: box model layers, padding vs margin, border position, box-sizing, margin collapse, shorthand notation, and individual border sides - All concepts follow schema requirements (explanation required, diagram optional)
213 lines
18 KiB
JSON
213 lines
18 KiB
JSON
{
|
|
"$schema": "../schemas/code-crispies-module-schema.json",
|
|
"id": "box-model",
|
|
"title": "CSS Box Model",
|
|
"description": "Master the fundamental principles of space management in web design through the CSS box model. This module explores how content, padding, borders, and margins combine to create layout structures that are both visually appealing and structurally sound.",
|
|
"difficulty": "beginner",
|
|
"lessons": [
|
|
{
|
|
"id": "box-model-1",
|
|
"title": "Box Model Components",
|
|
"description": "The CSS box model consists of four concentric layers: content area (innermost), padding, border, and margin (outermost). Understanding how these components interact is essential for precise layout control.",
|
|
"task": "Set <kbd>padding</kbd> to <kbd>1rem</kbd> to create space between the content and border.",
|
|
"previewHTML": "<div class=\"box\">Box Model Components</div>",
|
|
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background-color: lavender; border: 2px dashed slategray; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": ".box {\n ",
|
|
"initialCode": "",
|
|
"codeSuffix": "\n}",
|
|
"solution": "padding: 1rem;",
|
|
"previewContainer": "preview-area",
|
|
"concept": {
|
|
"explanation": "Every HTML element is a rectangular box made of four concentric layers. The content sits at the center, padding creates breathing room inside the box (keeping content away from edges), border wraps around the padding, and margin pushes neighboring elements away. Think of it like a framed picture: the image is content, the matting is padding, the frame is the border, and the wall space around it is margin.",
|
|
"diagram": "CSS Box Model (4 Layers)\n\n┌─────────────────────────────┐\n│ Margin (transparent) │\n│ ┌────────────────────────┐ │\n│ │ Border │ │\n│ │ ┌──────────────────┐ │ │\n│ │ │ Padding (inside) │ │ │\n│ │ │ ┌────────────┐ │ │ │\n│ │ │ │ Content │ │ │ │\n│ │ │ │ Area │ │ │ │\n│ │ │ └────────────┘ │ │ │\n│ │ └──────────────────┘ │ │\n│ └────────────────────────┘ │\n└─────────────────────────────┘"
|
|
},
|
|
"validations": [
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "padding", "expected": "1rem" },
|
|
"message": "Set <kbd>padding: 1rem</kbd>"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "box-model-2",
|
|
"title": "Adding Borders",
|
|
"description": "Borders outline an element, creating visual separation from surrounding content. The border shorthand accepts three values: width, style, and color.",
|
|
"task": "Set <kbd>border</kbd> to <kbd>2px solid darkslategray</kbd>.",
|
|
"previewHTML": "<div class=\"box\">This box needs a border</div>",
|
|
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background-color: mintcream; padding: 1rem; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": ".box {\n ",
|
|
"initialCode": "",
|
|
"codeSuffix": "\n}",
|
|
"solution": "border: 2px solid darkslategray;",
|
|
"previewContainer": "preview-area",
|
|
"concept": {
|
|
"explanation": "Borders sit between padding and margin, defining the visual edge of an element. They're unique in the box model because they're visible by default (unlike transparent padding and margin). The border shorthand combines three properties—width, style, and color—into one declaration. Borders add to an element's total size unless you use box-sizing: border-box.",
|
|
"diagram": "Border Position in Box Model\n\n┌─────────────────────┐\n│ Margin │ (outside)\n│ ╔═══════════════╗ │\n│ ║ Border (2px) ║ │ ← You are here\n│ ║ ┌─────────┐ ║ │\n│ ║ │ Padding │ ║ │\n│ ║ │ Content │ ║ │\n│ ║ └─────────┘ ║ │\n│ ╚═══════════════╝ │\n└─────────────────────┘"
|
|
},
|
|
"validations": [
|
|
{
|
|
"type": "regex",
|
|
"value": "border:\\s*2px\\s+solid\\s+darkslategray",
|
|
"message": "Set <kbd>border: 2px solid darkslategray</kbd>",
|
|
"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 <kbd>margin</kbd> to <kbd>1rem</kbd> to create space between this element and its neighbors.",
|
|
"previewHTML": "<div class=\"container\"><div class=\"outer\">This box needs margins</div><div class=\"neighbor\">Adjacent element</div></div>",
|
|
"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; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": ".outer {\n ",
|
|
"initialCode": "",
|
|
"codeSuffix": "\n}",
|
|
"solution": "margin: 1rem;",
|
|
"previewContainer": "preview-area",
|
|
"concept": {
|
|
"explanation": "Margins are the invisible space outside an element's border that pushes other elements away. Unlike padding (which is inside the border and gets the background color), margins are always transparent. They don't affect the element's own size—they control the relationship between elements. Margins can even be negative, pulling elements closer together or overlapping them.",
|
|
"diagram": "Margin vs Padding\n\n┌───────────────────────────┐\n│ ░░░░░ MARGIN ░░░░░ │ (transparent)\n│ ░ ┌─────────────────┐ ░ │\n│ ░ │ BORDER │ ░ │\n│ ░ │ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │ ░ │\n│ ░ │ ▓ PADDING ▓ │ ░ │ (gets background)\n│ ░ │ ▓ ┌─────────┐ ▓ │ ░ │\n│ ░ │ ▓ │ CONTENT │ ▓ │ ░ │\n│ ░ │ ▓ └─────────┘ ▓ │ ░ │\n│ ░ │ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │ ░ │\n│ ░ └─────────────────┘ ░ │\n│ ░░░░░░░░░░░░░░░░░░░░░░░ │\n└───────────────────────────┘"
|
|
},
|
|
"validations": [
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "margin", "expected": "1rem" },
|
|
"message": "Set <kbd>margin: 1rem</kbd>"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "box-model-4",
|
|
"title": "Box Sizing: Border-Box",
|
|
"description": "The <kbd>box-sizing</kbd> property determines how element dimensions are calculated. The default <kbd>content-box</kbd> excludes padding and border from width/height, while <kbd>border-box</kbd> includes them, making layout calculations more intuitive.",
|
|
"task": "Set <kbd>box-sizing</kbd> to <kbd>border-box</kbd> so padding and border are included in the width.",
|
|
"previewHTML": "<div class=\"sizing-demo\"><div class=\"box default\">Content-box (default)</div><div class=\"box sized\">Border-box</div></div>",
|
|
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .sizing-demo { display: flex; gap: 1rem; } .box { width: 200px; padding: 1rem; border: 4px solid teal; background: lightcyan; } .default { box-sizing: content-box; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": ".sized {\n ",
|
|
"initialCode": "",
|
|
"codeSuffix": "\n}",
|
|
"solution": "box-sizing: border-box;",
|
|
"previewContainer": "preview-area",
|
|
"concept": {
|
|
"explanation": "By default (content-box), when you set width: 200px, the browser makes only the content 200px wide, then adds padding and border on top—making the total width larger. With border-box, the browser makes the entire box 200px including padding and border, shrinking the content area to fit. Border-box makes layout math predictable: width: 200px means the element is exactly 200px wide, period.",
|
|
"diagram": "content-box vs border-box\n\nwidth: 200px + padding: 20px + border: 4px\n\ncontent-box (default):\n┌────────────────────────────┐\n│ Border (4px) │\n│ ┌──────────────────────┐ │\n│ │ Padding (20px) │ │\n│ │ ┌────────────────┐ │ │\n│ │ │ Content 200px │ │ │ Total: 248px!\n│ │ └────────────────┘ │ │\n│ └──────────────────────┘ │\n└────────────────────────────┘\n\nborder-box:\n┌──────────────────────┐\n│ Border + Padding │\n│ ┌────────────────┐ │\n│ │ Content ~152px │ │ Total: 200px ✓\n│ └────────────────┘ │\n└──────────────────────┘"
|
|
},
|
|
"validations": [
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "box-sizing", "expected": "border-box" },
|
|
"message": "Set <kbd>box-sizing: border-box</kbd>"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"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 <kbd>margin-bottom</kbd> to <kbd>2rem</kbd>. Notice the space between paragraphs equals 2rem (not 3rem) due to margin collapse.",
|
|
"previewHTML": "<div class=\"collapse-demo\"><p class=\"first\">This paragraph has a bottom margin.</p><p class=\"second\">This paragraph has a top margin of 1rem.</p></div>",
|
|
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .collapse-demo { border: 1px solid silver; padding: 8px; background: ghostwhite; } .second { margin-top: 1rem; background: linen; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": ".first {\n ",
|
|
"initialCode": "",
|
|
"codeSuffix": "\n}",
|
|
"solution": "margin-bottom: 2rem;",
|
|
"previewContainer": "preview-area",
|
|
"concept": {
|
|
"explanation": "When two vertical margins touch, they don't add up—they collapse into a single margin equal to the larger of the two. This prevents excessive spacing between stacked elements like paragraphs. If you have margin-bottom: 2rem and margin-top: 1rem, the total space is 2rem (not 3rem). Horizontal margins never collapse; only vertical ones do.",
|
|
"diagram": "Vertical Margin Collapse\n\nWithout collapse (expected?):\n┌─────────────┐\n│ Element 1 │\n└─────────────┘\n ↓ 2rem margin-bottom\n ↓ 1rem margin-top\n┌─────────────┐ Total: 3rem?\n│ Element 2 │\n└─────────────┘\n\nWith collapse (actual):\n┌─────────────┐\n│ Element 1 │\n└─────────────┘\n ↓\n ↓ 2rem (larger wins)\n ↓\n┌─────────────┐ Total: 2rem ✓\n│ Element 2 │\n└─────────────┘"
|
|
},
|
|
"validations": [
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "margin-bottom", "expected": "2rem" },
|
|
"message": "Set <kbd>margin-bottom: 2rem</kbd>"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "box-model-6",
|
|
"title": "Margin Shorthand Notation",
|
|
"description": "The margin shorthand can set all four sides at once. Two values set vertical (top/bottom) and horizontal (left/right) margins respectively.",
|
|
"task": "Set <kbd>margin</kbd> to <kbd>1rem 2rem</kbd> for 1rem top/bottom and 2rem left/right.",
|
|
"previewHTML": "<div class=\"container\"><div class=\"spaced\">This box needs margins: 1rem top/bottom, 2rem left/right</div></div>",
|
|
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .container { background-color: whitesmoke; padding: 8px; } .spaced { background-color: honeydew; border: 2px solid mediumseagreen; padding: 1rem; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": ".spaced {\n ",
|
|
"initialCode": "",
|
|
"codeSuffix": "\n}",
|
|
"solution": "margin: 1rem 2rem;",
|
|
"previewContainer": "preview-area",
|
|
"concept": {
|
|
"explanation": "The margin shorthand uses a clockwise pattern: one value applies to all sides, two values set vertical then horizontal, three values set top, horizontal, then bottom, and four values go clockwise from top (top, right, bottom, left). The two-value pattern is most common because vertical and horizontal spacing often differ. Think 'Y-axis first, X-axis second.'",
|
|
"diagram": "Margin Shorthand Patterns\n\nOne value:\nmargin: 1rem;\n → all sides: 1rem\n\nTwo values:\nmargin: 1rem 2rem;\n ↓ ↓\n vertical horizontal\n (Y) (X)\n\nFour values (clockwise):\nmargin: 1rem 2rem 3rem 4rem;\n ↓ ↓ ↓ ↓\n top right bottom left\n T R B L"
|
|
},
|
|
"validations": [
|
|
{
|
|
"type": "regex",
|
|
"value": "margin:\\s*1rem\\s+2rem",
|
|
"message": "Set <kbd>margin: 1rem 2rem</kbd>",
|
|
"options": { "caseSensitive": false }
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "box-model-7",
|
|
"title": "Padding Shorthand Notation",
|
|
"description": "Like margin, padding shorthand allows setting all sides at once. A single value applies to all four sides equally.",
|
|
"task": "Set <kbd>padding</kbd> to <kbd>2rem</kbd> to add equal padding on all sides.",
|
|
"previewHTML": "<div class=\"padded\">This box needs equal padding on all sides</div>",
|
|
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .padded { background-color: papayawhip; border: 2px solid orange; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": ".padded {\n ",
|
|
"initialCode": "",
|
|
"codeSuffix": "\n}",
|
|
"solution": "padding: 2rem;",
|
|
"previewContainer": "preview-area",
|
|
"concept": {
|
|
"explanation": "Padding shorthand follows the same clockwise pattern as margin: one value for all sides, two values for vertical/horizontal, four values for top/right/bottom/left. The key difference is that padding creates internal space (pushing content away from borders) while margin creates external space (pushing other elements away). Padding also inherits the element's background color.",
|
|
"diagram": "Padding Shorthand (same pattern)\n\npadding: 2rem;\n → Equal on all sides\n\n┌─────────────────────┐\n│ Border │\n│ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │ ← 2rem padding\n│ ▓ ┌───────────┐ ▓ │ (all sides)\n│ ▓ │ Content │ ▓ │\n│ ▓ └───────────┘ ▓ │\n│ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │\n└─────────────────────┘"
|
|
},
|
|
"validations": [
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "padding", "expected": "2rem" },
|
|
"message": "Set <kbd>padding: 2rem</kbd>"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "box-model-8",
|
|
"title": "Border on Specific Sides",
|
|
"description": "For granular control, you can target specific sides with <kbd>border-top</kbd>, <kbd>border-right</kbd>, <kbd>border-bottom</kbd>, or <kbd>border-left</kbd>.",
|
|
"task": "Set <kbd>border-bottom</kbd> to <kbd>4px solid dodgerblue</kbd>.",
|
|
"previewHTML": "<div class=\"line\">This element needs only a bottom border</div>",
|
|
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .line { padding: 1rem; background-color: aliceblue; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": ".line {\n ",
|
|
"initialCode": "",
|
|
"codeSuffix": "\n}",
|
|
"solution": "border-bottom: 4px solid dodgerblue;",
|
|
"previewContainer": "preview-area",
|
|
"concept": {
|
|
"explanation": "You can apply borders to individual sides using border-top, border-right, border-bottom, or border-left. This is common for creating underlines, dividers, or asymmetric designs. Each side can have different widths, styles, and colors. The shorthand border property is just a convenience—underneath, the browser sets all four sides at once.",
|
|
"diagram": "Individual Border Sides\n\nborder-bottom only:\n┌──────────────────┐\n│ │ (no border)\n│ Content │\n│ │\n└══════════════════┘ ← border-bottom\n\nMix and match:\nborder-left + border-bottom:\n ┌─────────────────┐\n ║ │\n ║ Content │\n ║ │\n ╚═════════════════╝"
|
|
},
|
|
"validations": [
|
|
{
|
|
"type": "regex",
|
|
"value": "border-bottom:\\s*4px\\s+solid\\s+dodgerblue",
|
|
"message": "Set <kbd>border-bottom: 4px solid dodgerblue</kbd>",
|
|
"options": { "caseSensitive": false }
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|