Files
code-crispies/lessons/es/00-basic-selectors.json
Michael Czechowski c560676544 feat: implement #4 — replace answer-revealing validation messages with pedagogical hints
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.
2026-03-28 19:40:28 +01:00

260 lines
15 KiB
JSON

{
"$schema": "../../schemas/code-crispies-module-schema.json",
"id": "css-basic-selectors",
"title": "Fundamentos de CSS",
"description": "Aprende los bloques fundamentales de CSS: propiedades, valores y selectores. Este módulo te enseña las reglas de sintaxis que sigue cada declaración CSS.",
"difficulty": "beginner",
"lessons": [
{
"id": "css-properties",
"title": "Propiedades CSS",
"description": "CSS estiliza elementos usando <strong>declaraciones</strong> - pares de propiedades y valores. Cada declaración sigue el mismo patrón:<br><br><pre>property: value;</pre><br>La <strong>propiedad</strong> es lo que quieres cambiar (como <kbd>color</kbd> o <kbd>background</kbd>). El <strong>valor</strong> es a lo que lo estableces. Dos puntos los separan, y un punto y coma termina la línea.<br><br>Los valores vienen en diferentes tipos:<br>• <strong>Palabras clave:</strong> <kbd>red</kbd>, <kbd>bold</kbd>, <kbd>center</kbd><br>• <strong>Números con unidades:</strong> <kbd>16px</kbd>, <kbd>2rem</kbd>, <kbd>100%</kbd><br>• <strong>Colores:</strong> <kbd>steelblue</kbd>, <kbd>#ff0000</kbd>",
"task": "Completa la declaración añadiendo <kbd>color: coral;</kbd> para cambiar el color del texto.",
"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": "¿Qué propiedad controla el color del texto?"
}
]
},
{
"id": "multiple-properties",
"title": "Múltiples propiedades",
"description": "Una regla puede tener múltiples declaraciones. Cada una va en su propia línea, y cada una necesita un punto y coma al final:<br><br><pre>.box {<br> background: gold;<br> color: navy;<br> padding: 1rem;<br>}</pre><br>El orden normalmente no importa - CSS las aplica todas. Cuando hay conflictos, la última gana.",
"task": "Añade dos declaraciones: <kbd>background: lavender;</kbd> y <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": "Revisa la propiedad <kbd>background</kbd>"
},
{
"type": "property_value",
"value": { "property": "padding", "expected": "1rem" },
"message": "La tarjeta necesita espacio dentro de sus bordes"
}
]
},
{
"id": "type-selectors",
"title": "Selectores de tipo",
"description": "Un <strong>selector</strong> le dice al navegador qué elementos estilizar. El selector más simple es un <strong>selector de tipo</strong> — simplemente el nombre de la etiqueta HTML.<br><br><pre>p {<br> color: steelblue;<br>}</pre><br>Esta regla apunta a cada elemento <kbd>&lt;p&gt;</kbd> en la página. Los selectores de tipo son geniales para establecer estilos base.",
"task": "Estiliza todos los párrafos. Escribe una regla con <kbd>p</kbd> como selector y establece <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": "Empieza con <kbd>p {</kbd> para seleccionar párrafos"
},
{
"type": "property_value",
"value": { "property": "color", "expected": "steelblue" },
"message": "¿Qué propiedad cambia el color del texto?"
}
]
},
{
"id": "styling-links",
"title": "Estilizando enlaces",
"description": "Los selectores de tipo funcionan para cualquier elemento HTML. El selector <kbd>a</kbd> apunta a todos los enlaces de una página.<br><br>Los enlaces tienen un color azul y subrayado por defecto. Puedes cambiar ambos con CSS — usa <kbd>color</kbd> para el texto y <kbd>text-decoration: none</kbd> para quitar el subrayado.",
"task": "Estiliza los enlaces de navegación. Escribe una regla con <kbd>a</kbd> como selector y establece <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": "Empieza con <kbd>a {</kbd> para seleccionar enlaces"
},
{
"type": "property_value",
"value": { "property": "color", "expected": "coral" },
"message": "¿Qué valor da un color cálido, rojo-anaranjado?"
}
]
},
{
"id": "class-selectors",
"title": "Selectores de clase",
"description": "Los selectores de tipo estilizan <em>todos</em> los elementos de ese tipo. ¿Pero qué si quieres estilizar solo algunos de ellos?<br><br>Los <strong>selectores de clase</strong> apuntan a elementos con un atributo <kbd>class</kbd> específico. Empiezan con un punto:<br><br><pre>.badge {<br> background: coral;<br>}</pre><br>Esto estiliza solo elementos con <kbd>class=\"badge\"</kbd>.",
"task": "Estiliza el badge de notificación. Escribe una regla con <kbd>.badge</kbd> como selector y establece <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": "Empieza con <kbd>.badge {</kbd> (¡no olvides el punto!)"
},
{
"type": "property_value",
"value": { "property": "background", "expected": "tomato" },
"message": "El badge necesita un fondo rojo brillante"
}
]
},
{
"id": "button-variants",
"title": "Variantes de botón",
"description": "Los elementos pueden tener múltiples clases. Cuando encadenas selectores de clase sin espacios, apuntas a elementos que tienen <em>todas</em> esas clases:<br><br><pre>.btn.primary {<br> background: steelblue;<br>}</pre><br>Esto apunta a elementos con <kbd>class=\"btn primary\"</kbd>, no solo <kbd>.btn</kbd> o solo <kbd>.primary</kbd>.",
"task": "Estiliza el botón primario. Escribe una regla con <kbd>.btn.primary</kbd> como selector y establece <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": "Usa <kbd>.btn.primary {</kbd> (sin espacio entre clases)"
},
{
"type": "property_value",
"value": { "property": "background", "expected": "steelblue" },
"message": "¿Qué propiedad establece el color de relleno del botón?"
}
]
},
{
"id": "specific-elements",
"title": "Apuntando a elementos específicos",
"description": "A veces quieres que una clase se vea diferente en diferentes elementos. Combina un selector de tipo con un selector de clase (sin espacio) para ser más específico:<br><br><pre>a.btn {<br> text-decoration: none;<br>}</pre><br>Esto estiliza solo elementos <kbd>&lt;a&gt;</kbd> con la clase <kbd>btn</kbd>, no elementos <kbd>&lt;button&gt;</kbd> con esa clase.",
"task": "Quita el subrayado de los botones-enlace. Escribe una regla con <kbd>a.btn</kbd> como selector y establece <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": "Usa <kbd>a.btn {</kbd> (tipo + clase, sin espacio)"
},
{
"type": "property_value",
"value": { "property": "text-decoration", "expected": "none" },
"message": "¿Qué propiedad controla el subrayado de los enlaces?"
}
]
},
{
"id": "grouping-selectors",
"title": "Agrupando selectores",
"description": "Cuando múltiples elementos necesitan los mismos estilos, lístalos separados por comas. Esto mantiene tu CSS limpio y mantenible.<br><br><pre>h1, h2, h3 {<br> color: steelblue;<br>}</pre><br>Esto aplica el mismo color a los tres niveles de encabezado en una regla.",
"task": "Estiliza todos los encabezados consistentemente. Añade <kbd>color: steelblue</kbd> al selector agrupado <kbd>h1, h2, h3</kbd>.",
"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": "Revisa la propiedad <kbd>color</kbd>"
}
]
},
{
"id": "descendant-selectors",
"title": "Selectores descendientes",
"description": "Apunta a elementos dentro de otros elementos usando un espacio entre selectores. Este es uno de los patrones más útiles en CSS.<br><br><pre>.nav a {<br> color: white;<br>}</pre><br>Esto estiliza solo enlaces dentro de <kbd>.nav</kbd>, dejando otros enlaces sin cambios.",
"task": "Estiliza los enlaces de navegación diferente. Escribe una regla con <kbd>.nav a</kbd> como selector y establece <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": "Usa <kbd>.nav a {</kbd> (espacio entre .nav y a)"
},
{
"type": "property_value",
"value": { "property": "color", "expected": "white" },
"message": "Los enlaces necesitan destacar sobre el fondo azul"
}
]
},
{
"id": "nested-styling",
"title": "Estilos anidados",
"description": "Los selectores descendientes te permiten crear estilos contextuales. El mismo elemento puede verse diferente dependiendo de dónde aparezca.<br><br>Por ejemplo, los párrafos en una <kbd>.card</kbd> podrían ser más pequeños que los párrafos en un <kbd>article</kbd>.",
"task": "Haz los párrafos dentro de la tarjeta más pequeños. Escribe una regla con <kbd>.card p</kbd> como selector y establece <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": "Usa <kbd>.card p {</kbd> (espacio entre .card y p)"
},
{
"type": "property_value",
"value": { "property": "font-size", "expected": "0.9rem" },
"message": "Revisa la propiedad <kbd>font-size</kbd> — el texto debería ser ligeramente más pequeño"
}
]
}
]
}