Rewrite ~120 validation error messages across 17 English lesson modules and their localized variants (ar, de, es, pl, uk) to use concept questions, property hints, and directional nudges instead of revealing the exact CSS property-value answers. Priority modules (flexbox, box-model, colors, positioning) fully rewritten. All remaining CSS modules updated. Only message strings changed — no validation logic modifications.
260 lines
14 KiB
JSON
260 lines
14 KiB
JSON
{
|
|
"$schema": "../schemas/code-crispies-module-schema.json",
|
|
"id": "css-basic-selectors",
|
|
"title": "CSS Basics",
|
|
"description": "Learn the fundamental building blocks of CSS: properties, values, and selectors. This module teaches you the syntax rules that every CSS declaration follows.",
|
|
"difficulty": "beginner",
|
|
"lessons": [
|
|
{
|
|
"id": "css-properties",
|
|
"title": "CSS Properties",
|
|
"description": "CSS styles elements using <strong>declarations</strong> - pairs of properties and values. Every declaration follows the same pattern:<br><br><pre>property: value;</pre><br>The <strong>property</strong> is what you want to change (like <kbd>color</kbd> or <kbd>background</kbd>). The <strong>value</strong> is what you're setting it to. A colon separates them, and a semicolon ends the line.<br><br>Values come in different types:<br>• <strong>Keywords:</strong> <kbd>red</kbd>, <kbd>bold</kbd>, <kbd>center</kbd><br>• <strong>Numbers with units:</strong> <kbd>16px</kbd>, <kbd>2rem</kbd>, <kbd>100%</kbd><br>• <strong>Colors:</strong> <kbd>steelblue</kbd>, <kbd>#ff0000</kbd>",
|
|
"task": "Complete the declaration by adding <kbd>color: coral;</kbd> to change the text color.",
|
|
"previewHTML": "<p class=\"text\">This text should turn coral.</p>",
|
|
"previewBaseCSS": "body { font-family: system-ui; padding: 20px; } .text { font-size: 1.25rem; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": ".text {\n ",
|
|
"initialCode": "",
|
|
"codeSuffix": "\n}",
|
|
"previewContainer": "preview-area",
|
|
"solution": "color: coral;",
|
|
"validations": [
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "color", "expected": "coral" },
|
|
"message": "Which property controls text color?"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "multiple-properties",
|
|
"title": "Multiple Properties",
|
|
"description": "A rule can have multiple declarations. Each one goes on its own line, and each needs a semicolon at the end:<br><br><pre>.box {<br> background: gold;<br> color: navy;<br> padding: 1rem;<br>}</pre><br>The order usually doesn't matter - CSS applies them all. When properties conflict, the last one wins.",
|
|
"task": "Add two declarations: <kbd>background: lavender;</kbd> and <kbd>padding: 1rem;</kbd>",
|
|
"previewHTML": "<div class=\"card\">A styled card with background and padding.</div>",
|
|
"previewBaseCSS": "body { font-family: system-ui; padding: 20px; } .card { border-radius: 8px; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": ".card {\n ",
|
|
"initialCode": "",
|
|
"codeSuffix": "\n}",
|
|
"previewContainer": "preview-area",
|
|
"solution": "background: lavender;\n padding: 1rem;",
|
|
"validations": [
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "background", "expected": "lavender" },
|
|
"message": "Check the <kbd>background</kbd> property"
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "padding", "expected": "1rem" },
|
|
"message": "The card needs space inside its edges"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "type-selectors",
|
|
"title": "Type Selectors",
|
|
"description": "A <strong>selector</strong> tells the browser which elements to style. The simplest selector is a <strong>type selector</strong> — just the HTML tag name.<br><br><pre>p {<br> color: steelblue;<br>}</pre><br>This rule targets every <kbd><p></kbd> element on the page. Type selectors are great for setting base styles.",
|
|
"task": "Style all paragraphs. Write a rule with <kbd>p</kbd> as the selector and set <kbd>color: steelblue</kbd>.",
|
|
"previewHTML": "<article>\n <h2>Fresh Roasted Coffee</h2>\n <p>Our beans are sourced from small farms in Colombia and Ethiopia.</p>\n <p>Each batch is roasted weekly to ensure peak freshness.</p>\n</article>",
|
|
"previewBaseCSS": "body { font-family: system-ui; padding: 1rem; } h2 { margin: 0 0 1rem; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": "",
|
|
"initialCode": "",
|
|
"codeSuffix": "",
|
|
"previewContainer": "preview-area",
|
|
"solution": "p {\n color: steelblue;\n}",
|
|
"validations": [
|
|
{
|
|
"type": "regex",
|
|
"value": "p\\s*\\{",
|
|
"message": "Start with <kbd>p {</kbd> to select paragraphs"
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "color", "expected": "steelblue" },
|
|
"message": "Which property changes text color?"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "styling-links",
|
|
"title": "Styling Links",
|
|
"description": "Type selectors work for any HTML element. The <kbd>a</kbd> selector targets all links on a page.<br><br>Links have a default blue color and underline. You can change both with CSS — use <kbd>color</kbd> for the text and <kbd>text-decoration: none</kbd> to remove the underline.",
|
|
"task": "Style the navigation links. Write a rule with <kbd>a</kbd> as the selector and set <kbd>color: coral</kbd>.",
|
|
"previewHTML": "<nav>\n <a href=\"#\">Home</a>\n <a href=\"#\">Menu</a>\n <a href=\"#\">About</a>\n <a href=\"#\">Contact</a>\n</nav>",
|
|
"previewBaseCSS": "body { font-family: system-ui; padding: 1rem; } nav { display: flex; gap: 1.5rem; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": "",
|
|
"initialCode": "",
|
|
"codeSuffix": "",
|
|
"previewContainer": "preview-area",
|
|
"solution": "a {\n color: coral;\n}",
|
|
"validations": [
|
|
{
|
|
"type": "regex",
|
|
"value": "a\\s*\\{",
|
|
"message": "Start with <kbd>a {</kbd> to select links"
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "color", "expected": "coral" },
|
|
"message": "What value gives a warm, reddish-orange color?"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "class-selectors",
|
|
"title": "Class Selectors",
|
|
"description": "Type selectors style <em>all</em> elements of that type. But what if you want to style just some of them?<br><br><strong>Class selectors</strong> target elements with a specific <kbd>class</kbd> attribute. They start with a dot:<br><br><pre>.badge {<br> background: coral;<br>}</pre><br>This styles only elements with <kbd>class=\"badge\"</kbd>.",
|
|
"task": "Style the notification badge. Write a rule with <kbd>.badge</kbd> as the selector and set <kbd>background: tomato</kbd>.",
|
|
"previewHTML": "<header>\n <h1>Dashboard</h1>\n <span class=\"badge\">3</span>\n</header>\n<p>You have new notifications waiting.</p>",
|
|
"previewBaseCSS": "body { font-family: system-ui; padding: 1rem; } header { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1rem; } h1 { margin: 0; font-size: 1.5rem; } .badge { color: white; padding: 0.25rem 0.5rem; border-radius: 999px; font-size: 0.875rem; } p { color: #555; margin: 0; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": "",
|
|
"initialCode": "",
|
|
"codeSuffix": "",
|
|
"previewContainer": "preview-area",
|
|
"solution": ".badge {\n background: tomato;\n}",
|
|
"validations": [
|
|
{
|
|
"type": "regex",
|
|
"value": "\\.badge\\s*\\{",
|
|
"message": "Start with <kbd>.badge {</kbd> (don't forget the dot!)"
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "background", "expected": "tomato" },
|
|
"message": "The badge needs a bright red background"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "button-variants",
|
|
"title": "Button Variants",
|
|
"description": "Elements can have multiple classes. When you chain class selectors without spaces, you target elements that have <em>all</em> those classes:<br><br><pre>.btn.primary {<br> background: steelblue;<br>}</pre><br>This targets elements with both <kbd>class=\"btn primary\"</kbd>, not just <kbd>.btn</kbd> or just <kbd>.primary</kbd>.",
|
|
"task": "Style the primary button. Write a rule with <kbd>.btn.primary</kbd> as the selector and set <kbd>background: steelblue</kbd>.",
|
|
"previewHTML": "<div class=\"actions\">\n <button class=\"btn\">Cancel</button>\n <button class=\"btn primary\">Save Changes</button>\n</div>",
|
|
"previewBaseCSS": "body { font-family: system-ui; padding: 1rem; } .actions { display: flex; gap: 0.75rem; } .btn { padding: 0.5rem 1rem; border: none; border-radius: 6px; font-size: 1rem; cursor: pointer; background: #e0e0e0; color: #333; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": "",
|
|
"initialCode": "",
|
|
"codeSuffix": "",
|
|
"previewContainer": "preview-area",
|
|
"solution": ".btn.primary {\n background: steelblue;\n}",
|
|
"validations": [
|
|
{
|
|
"type": "regex",
|
|
"value": "\\.btn\\.primary\\s*\\{",
|
|
"message": "Use <kbd>.btn.primary {</kbd> (no space between classes)"
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "background", "expected": "steelblue" },
|
|
"message": "Which property sets the button's fill color?"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "specific-elements",
|
|
"title": "Targeting Specific Elements",
|
|
"description": "Sometimes you want a class to look different on different elements. Combine a type selector with a class selector (no space) to be more specific:<br><br><pre>a.btn {<br> text-decoration: none;<br>}</pre><br>This styles only <kbd><a></kbd> elements with the <kbd>btn</kbd> class, not <kbd><button></kbd> elements with that class.",
|
|
"task": "Remove the underline from link buttons. Write a rule with <kbd>a.btn</kbd> as the selector and set <kbd>text-decoration: none</kbd>.",
|
|
"previewHTML": "<div class=\"actions\">\n <button class=\"btn\">Regular Button</button>\n <a href=\"#\" class=\"btn\">Link Button</a>\n</div>",
|
|
"previewBaseCSS": "body { font-family: system-ui; padding: 1rem; } .actions { display: flex; gap: 0.75rem; align-items: center; } .btn { padding: 0.5rem 1rem; border: none; border-radius: 6px; font-size: 1rem; cursor: pointer; background: steelblue; color: white; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": "",
|
|
"initialCode": "",
|
|
"codeSuffix": "",
|
|
"previewContainer": "preview-area",
|
|
"solution": "a.btn {\n text-decoration: none;\n}",
|
|
"validations": [
|
|
{
|
|
"type": "regex",
|
|
"value": "a\\.btn\\s*\\{",
|
|
"message": "Use <kbd>a.btn {</kbd> (type + class, no space)"
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "text-decoration", "expected": "none" },
|
|
"message": "Which property controls the underline on links?"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "grouping-selectors",
|
|
"title": "Grouping Selectors",
|
|
"description": "When multiple elements need the same styles, list them separated by commas. This keeps your CSS clean and maintainable.<br><br><pre>h1, h2, h3 {<br> color: steelblue;<br>}</pre><br>This applies the same color to all three heading levels in one rule.",
|
|
"task": "Style all headings consistently. Add <kbd>color: steelblue</kbd> to the grouped <kbd>h1, h2, h3</kbd> selector.",
|
|
"previewHTML": "<article><h1>Main Title</h1><p>Introduction paragraph with some text.</p><h2>Section Heading</h2><p>More content here.</p><h3>Subsection</h3><p>Final paragraph.</p></article>",
|
|
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } article { max-width: 500px; } p { color: #555; line-height: 1.6; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": "h1, h2, h3 {\n ",
|
|
"initialCode": "",
|
|
"codeSuffix": "\n}",
|
|
"previewContainer": "preview-area",
|
|
"solution": "color: steelblue;",
|
|
"validations": [
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "color", "expected": "steelblue" },
|
|
"message": "Check the <kbd>color</kbd> property"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "descendant-selectors",
|
|
"title": "Descendant Selectors",
|
|
"description": "Target elements inside other elements using a space between selectors. This is one of the most useful patterns in CSS.<br><br><pre>.nav a {<br> color: white;<br>}</pre><br>This styles only links inside <kbd>.nav</kbd>, leaving other links unchanged.",
|
|
"task": "Style navigation links differently. Write a rule with <kbd>.nav a</kbd> as the selector and set <kbd>color: white</kbd>.",
|
|
"previewHTML": "<nav class=\"nav\"><a href=\"#\">Home</a><a href=\"#\">About</a><a href=\"#\">Contact</a></nav><p>Read more in our <a href=\"#\">documentation</a>.</p>",
|
|
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; margin: 0; } .nav { background: steelblue; padding: 1rem; display: flex; gap: 1rem; border-radius: 8px; margin-bottom: 1rem; } .nav a { text-decoration: none; } p a { color: steelblue; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": "",
|
|
"initialCode": "",
|
|
"codeSuffix": "",
|
|
"previewContainer": "preview-area",
|
|
"solution": ".nav a {\n color: white;\n}",
|
|
"validations": [
|
|
{
|
|
"type": "regex",
|
|
"value": "\\.nav\\s+a\\s*\\{",
|
|
"message": "Use <kbd>.nav a {</kbd> (space between .nav and a)"
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "color", "expected": "white" },
|
|
"message": "The links need to stand out against the blue background"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "nested-styling",
|
|
"title": "Nested Styling",
|
|
"description": "Descendant selectors let you create contextual styles. The same element can look different depending on where it appears.<br><br>For example, paragraphs in a <kbd>.card</kbd> might be smaller than paragraphs in an <kbd>article</kbd>.",
|
|
"task": "Make paragraphs inside the card smaller. Write a rule with <kbd>.card p</kbd> as the selector and set <kbd>font-size: 0.9rem</kbd>.",
|
|
"previewHTML": "<article><h2>Article Title</h2><p>This is a regular article paragraph with normal-sized text for comfortable reading.</p><div class=\"card\"><strong>Quick Tip</strong><p>Card paragraphs should be slightly smaller to fit the compact design.</p></div><p>Back to regular article text here.</p></article>",
|
|
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } article { max-width: 500px; } h2 { color: steelblue; margin-top: 0; } p { line-height: 1.6; color: #444; } .card { background: #f0f4f8; padding: 1rem; border-radius: 8px; border-left: 4px solid steelblue; } .card strong { color: steelblue; display: block; margin-bottom: 0.5rem; }",
|
|
"sandboxCSS": "",
|
|
"codePrefix": "",
|
|
"initialCode": "",
|
|
"codeSuffix": "",
|
|
"previewContainer": "preview-area",
|
|
"solution": ".card p {\n font-size: 0.9rem;\n}",
|
|
"validations": [
|
|
{
|
|
"type": "regex",
|
|
"value": "\\.card\\s+p\\s*\\{",
|
|
"message": "Use <kbd>.card p {</kbd> (space between .card and p)"
|
|
},
|
|
{
|
|
"type": "property_value",
|
|
"value": { "property": "font-size", "expected": "0.9rem" },
|
|
"message": "Check the <kbd>font-size</kbd> property — the text should be slightly smaller"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|