Files
code-crispies/lessons/flexbox.json

204 lines
14 KiB
JSON

{
"$schema": "../schemas/code-crispies-module-schema.json",
"id": "flexbox",
"title": "CSS Flexbox",
"description": "Master the flexible box layout model for modern responsive designs",
"difficulty": "intermediate",
"lessons": [
{
"id": "flexbox-1",
"title": "Container",
"description": "Learn how to create a flex container and understand the main and cross axes.<br><br><pre>.container {\n display: flex;\n justify-content: center;\n align-items: center;\n}</pre>",
"task": "Add <kbd>display: flex</kbd> to <kbd>.wrap</kbd> to create a flexbox layout.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>",
"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 ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "display: flex;",
"previewContainer": "preview-area",
"concept": {
"explanation": "Setting display: flex creates a flex container, which establishes a new flex formatting context for its direct children. By default, this creates a horizontal main axis (left to right) and a vertical cross axis (top to bottom). All direct children automatically become flex items that can be controlled by flex properties.",
"diagram": "┌─────────────────────────────────┐\n│ FLEX CONTAINER (.wrap) │\n│ │\n│ Main Axis (horizontal) → │\n│ ┌───┐ ┌───┐ ┌───┐ │\n│ │ 1 │ │ 2 │ │ 3 │ ← Items │\n│ └───┘ └───┘ └───┘ │\n│ ↑ │\n│ Cross Axis (vertical) │\n└─────────────────────────────────┘",
"containerVsItem": "display: flex is a CONTAINER property applied to the parent element. It affects how the container lays out its children, but doesn't change the children themselves."
},
"validations": [
{
"type": "property_value",
"value": {
"property": "display",
"expected": "flex"
},
"message": "Set <kbd>display: flex</kbd>"
}
]
},
{
"id": "flexbox-2",
"title": "Direction & Wrap",
"description": "Control the direction and wrapping of flex items within a container.",
"task": "Add <kbd>flex-direction: column</kbd> and <kbd>flex-wrap: wrap</kbd> to <kbd>.wrap</kbd>.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div><div class='box'>4</div><div class='box'>5</div></div>",
"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; }",
"sandboxCSS": ".wrap { border: 2px dashed #aaa; padding: 1rem; height: 16rem; display: flex; }",
"codePrefix": ".wrap {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "flex-direction: column;\n flex-wrap: wrap;",
"previewContainer": "preview-area",
"concept": {
"explanation": "flex-direction changes which axis is the main axis: row (default) flows horizontally, while column flows vertically. This swaps how justify-content and align-items work. flex-wrap allows items to wrap onto new lines when they don't fit, instead of shrinking or overflowing.",
"diagram": "flex-direction: column\n\n┌──────────────┐\n│ Container │\n│ │\n│ ┌──┐ ┌──┐ │ Main Axis\n│ │1 │ │4 │ │ ↓\n│ └──┘ └──┘ │ (vertical)\n│ ┌──┐ ┌──┐ │\n│ │2 │ │5 │ │\n│ └──┘ └──┘ │ ← Cross Axis\n│ ┌──┐ │ (horizontal)\n│ │3 │ │\n│ └──┘ │\n└──────────────┘",
"containerVsItem": "Both flex-direction and flex-wrap are CONTAINER properties. They control how the container arranges its children, not the children themselves."
},
"validations": [
{
"type": "property_value",
"value": {
"property": "flex-direction",
"expected": "column"
},
"message": "Set <kbd>flex-direction: column</kbd>",
"options": {
"exact": true
}
},
{
"type": "property_value",
"value": {
"property": "flex-wrap",
"expected": "wrap"
},
"message": "Set <kbd>flex-wrap: wrap</kbd>",
"options": {
"exact": true
}
}
]
},
{
"id": "flexbox-3",
"title": "Justify Content",
"description": "Learn how to align flex items along the main axis of the flex container.",
"task": "Add <kbd>justify-content: space-between</kbd> to <kbd>.wrap</kbd> to distribute the boxes evenly.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>",
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background: steelblue; color: white; padding: 1rem; text-align: center; font-weight: bold; width: 3rem; height: 3rem; display: flex; align-items: center; justify-content: center; }",
"sandboxCSS": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; }",
"codePrefix": ".wrap {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "justify-content: space-between;",
"previewContainer": "preview-area",
"concept": {
"explanation": "justify-content controls how flex items are distributed along the main axis (horizontal by default). space-between places the first item at the start, the last at the end, and distributes remaining items with equal spacing between them. Other values include flex-start, center, flex-end, and space-around.",
"diagram": "justify-content: space-between\n\n┌─────────────────────────────┐\n│ ┌───┐ ┌───┐ ┌───┐ │\n│ │ 1 │ │ 2 │ │ 3 │ │\n│ └───┘ └───┘ └───┘ │\n│ ↑ ↑ ↑ │\n│ start equal gap end │\n│◄──────────────────────────► │\n│ Main Axis │\n└─────────────────────────────┘",
"containerVsItem": "justify-content is a CONTAINER property. The parent controls how its children are spaced, not the children themselves."
},
"validations": [
{
"type": "property_value",
"value": {
"property": "justify-content",
"expected": "space-between"
},
"message": "Set <kbd>justify-content: space-between</kbd>",
"options": {
"exact": true
}
}
]
},
{
"id": "flexbox-4",
"title": "Align Items",
"description": "Control how flex items are aligned along the cross axis of the flex container.",
"task": "Add <kbd>align-items: center</kbd> to <kbd>.wrap</kbd> to vertically center the boxes.",
"previewHTML": "<div class='wrap'><div class='box tall'>1</div><div class='box'>2</div><div class='box short'>3</div></div>",
"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; display: flex; justify-content: center; } .tall { height: 6rem; } .short { height: 3rem; }",
"sandboxCSS": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 10rem; }",
"codePrefix": ".wrap {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "align-items: center;",
"previewContainer": "preview-area",
"concept": {
"explanation": "align-items controls how flex items are aligned along the cross axis (vertical by default). While justify-content handles spacing along the main axis, align-items handles alignment perpendicular to it. The center value aligns all items to the middle of the cross axis, regardless of their individual heights.",
"diagram": "align-items: center\n\n┌──────────────────────┐ ↑\n│ │ │\n│ ┌────┐ │ │ Cross\n│ │ 1 │ ┌──┐ │ │ Axis\n│ │ │ │2 │ ┌─┐ │ │\n│ ────┼────┼──┼──┼─┼─┼─│ center line\n│ │ │ └──┘ └─┘ │ │\n│ └────┘ 3 │ │\n│ │ ↓\n└──────────────────────┘",
"containerVsItem": "align-items is a CONTAINER property that sets the default cross-axis alignment for all child items. Individual items can override this with align-self."
},
"validations": [
{
"type": "property_value",
"value": {
"property": "align-items",
"expected": "center"
},
"message": "Set <kbd>align-items: center</kbd>",
"options": {
"exact": true
}
}
]
},
{
"id": "flexbox-5",
"title": "Flex Grow",
"description": "The <kbd>flex</kbd> property controls how much an item grows relative to others.",
"task": "Add <kbd>flex: 2</kbd> to <kbd>.box2</kbd> to make it grow twice as wide.",
"previewHTML": "<div class='wrap'><div class='box box1'>1</div><div class='box box2'>2</div><div class='box box3'>3</div></div>",
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { color: white; padding: 1rem; margin: 8px; text-align: center; font-weight: bold; display: flex; align-items: center; justify-content: center; } .box1 { background: coral; flex: 1; } .box2 { background: mediumseagreen; } .box3 { background: gold; flex: 1; }",
"sandboxCSS": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; }",
"codePrefix": ".box2 {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "flex: 2;",
"previewContainer": "preview-area",
"concept": {
"explanation": "The flex property controls how flex items grow to fill available space. It's shorthand for flex-grow, flex-shrink, and flex-basis. When you set flex: 2, the item gets 2 \"shares\" of leftover space, while flex: 1 items get 1 share each. This creates proportional sizing based on the numbers you provide.",
"diagram": "flex: 2 vs flex: 1\n\n┌────────────────────────────┐\n│ Available Space │\n├────────┬──────────┬────────┤\n│ Box 1 │ Box 2 │ Box 3 │\n│ flex:1 │ flex:2 │ flex:1 │\n│ 25% │ 50% │ 25% │\n│ (1/4) │ (2/4) │ (1/4) │\n└────────┴──────────┴────────┘\n 1 share 2 shares 1 share",
"containerVsItem": "flex is an ITEM property, unlike the container properties we've seen. It's applied to individual children to control how they grow, not to the parent."
},
"validations": [
{
"type": "property_value",
"value": {
"property": "flex",
"expected": "2"
},
"message": "Set <kbd>flex: 2</kbd>"
}
]
},
{
"id": "flexbox-6",
"title": "Align Self",
"description": "Use <kbd>align-self</kbd> to override alignment for a single flex item.",
"task": "Add <kbd>align-self: flex-start</kbd> to <kbd>.middle</kbd> to move it to the top.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box middle'>2</div><div class='box'>3</div></div>",
"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 ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "align-self: flex-start;",
"previewContainer": "preview-area",
"concept": {
"explanation": "align-self allows a single flex item to override the container's align-items setting. While the container sets the default cross-axis alignment for all children, individual items can break free and align themselves differently. This is useful when one item needs special positioning without affecting the others.",
"diagram": "align-self: flex-start\n\n┌──────────────────────┐ ↑\n│ ┌─┐ │ │\n│ │2│ ← flex-start │ │\n│ └─┘ │ │ Cross\n│ ┌──┐ ┌──┐ │ │ Axis\n│ ──────│1 │────│3 │──│ ← center (default)\n│ └──┘ └──┘ │ │\n│ │ │\n│ │ ↓\n└──────────────────────┘",
"containerVsItem": "align-self is an ITEM property that overrides the container's align-items. This is the first property that gives individual children control over their own positioning."
},
"validations": [
{
"type": "property_value",
"value": {
"property": "align-self",
"expected": "flex-start"
},
"message": "Set <kbd>align-self: flex-start</kbd>"
}
]
}
]
}