{ "$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.

.container {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n}
", "task": "Add display: flex to .wrap to create a flexbox layout.", "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 ", "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 display: flex" } ] }, { "id": "flexbox-2", "title": "Direction & Wrap", "description": "Control the direction and wrapping of flex items within a container.", "task": "Add flex-direction: column and flex-wrap: wrap to .wrap.", "previewHTML": "
1
2
3
4
5
", "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 flex-direction: column", "options": { "exact": true } }, { "type": "property_value", "value": { "property": "flex-wrap", "expected": "wrap" }, "message": "Set flex-wrap: wrap", "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 justify-content: space-between to .wrap to distribute the boxes evenly.", "previewHTML": "
1
2
3
", "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 justify-content: space-between", "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 align-items: center to .wrap to vertically center the boxes.", "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; 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 align-items: center", "options": { "exact": true } } ] }, { "id": "flexbox-5", "title": "Flex Grow", "description": "The flex property controls how much an item grows relative to others.", "task": "Add flex: 2 to .box2 to make it grow twice as wide.", "previewHTML": "
1
2
3
", "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 flex: 2" } ] }, { "id": "flexbox-6", "title": "Align Self", "description": "Use align-self to override alignment for a single flex item.", "task": "Add align-self: flex-start to .middle to move it to the top.", "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; 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 align-self: flex-start" } ] } ] }