{ "$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 declaraciones - pares de propiedades y valores. Cada declaración sigue el mismo patrón:

property: value;

La propiedad es lo que quieres cambiar (como color o background). El valor es a lo que lo estableces. Dos puntos los separan, y un punto y coma termina la línea.

Los valores vienen en diferentes tipos:
Palabras clave: red, bold, center
Números con unidades: 16px, 2rem, 100%
Colores: steelblue, #ff0000", "task": "Completa la declaración añadiendo color: coral; para cambiar el color del texto.", "previewHTML": "

This text should turn coral.

", "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": "Añade color: coral;" } ] }, { "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:

.box {
background: gold;
color: navy;
padding: 1rem;
}

El orden normalmente no importa - CSS las aplica todas. Cuando hay conflictos, la última gana.", "task": "Añade dos declaraciones: background: lavender; y padding: 1rem;", "previewHTML": "
A styled card with background and padding.
", "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": "Añade background: lavender;" }, { "type": "property_value", "value": { "property": "padding", "expected": "1rem" }, "message": "Añade padding: 1rem;" } ] }, { "id": "type-selectors", "title": "Selectores de tipo", "description": "Un selector le dice al navegador qué elementos estilizar. El selector más simple es un selector de tipo — simplemente el nombre de la etiqueta HTML.

p {
color: steelblue;
}

Esta regla apunta a cada elemento <p> en la página. Los selectores de tipo son geniales para establecer estilos base.", "task": "Estiliza todos los párrafos. Escribe una regla con p como selector y establece color: steelblue.", "previewHTML": "
\n

Fresh Roasted Coffee

\n

Our beans are sourced from small farms in Colombia and Ethiopia.

\n

Each batch is roasted weekly to ensure peak freshness.

\n
", "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 p { para seleccionar párrafos" }, { "type": "property_value", "value": { "property": "color", "expected": "steelblue" }, "message": "Establece color: steelblue" } ] }, { "id": "styling-links", "title": "Estilizando enlaces", "description": "Los selectores de tipo funcionan para cualquier elemento HTML. El selector a apunta a todos los enlaces de una página.

Los enlaces tienen un color azul y subrayado por defecto. Puedes cambiar ambos con CSS — usa color para el texto y text-decoration: none para quitar el subrayado.", "task": "Estiliza los enlaces de navegación. Escribe una regla con a como selector y establece color: coral.", "previewHTML": "", "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 a { para seleccionar enlaces" }, { "type": "property_value", "value": { "property": "color", "expected": "coral" }, "message": "Establece color: coral" } ] }, { "id": "class-selectors", "title": "Selectores de clase", "description": "Los selectores de tipo estilizan todos los elementos de ese tipo. ¿Pero qué si quieres estilizar solo algunos de ellos?

Los selectores de clase apuntan a elementos con un atributo class específico. Empiezan con un punto:

.badge {
background: coral;
}

Esto estiliza solo elementos con class=\"badge\".", "task": "Estiliza el badge de notificación. Escribe una regla con .badge como selector y establece background: tomato.", "previewHTML": "
\n

Dashboard

\n 3\n
\n

You have new notifications waiting.

", "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 .badge { (¡no olvides el punto!)" }, { "type": "property_value", "value": { "property": "background", "expected": "tomato" }, "message": "Establece background: tomato" } ] }, { "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 todas esas clases:

.btn.primary {
background: steelblue;
}

Esto apunta a elementos con class=\"btn primary\", no solo .btn o solo .primary.", "task": "Estiliza el botón primario. Escribe una regla con .btn.primary como selector y establece background: steelblue.", "previewHTML": "
\n \n \n
", "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 .btn.primary { (sin espacio entre clases)" }, { "type": "property_value", "value": { "property": "background", "expected": "steelblue" }, "message": "Establece background: steelblue" } ] }, { "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:

a.btn {
text-decoration: none;
}

Esto estiliza solo elementos <a> con la clase btn, no elementos <button> con esa clase.", "task": "Quita el subrayado de los botones-enlace. Escribe una regla con a.btn como selector y establece text-decoration: none.", "previewHTML": "
\n \n Link Button\n
", "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 a.btn { (tipo + clase, sin espacio)" }, { "type": "property_value", "value": { "property": "text-decoration", "expected": "none" }, "message": "Establece text-decoration: none" } ] }, { "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.

h1, h2, h3 {
color: steelblue;
}

Esto aplica el mismo color a los tres niveles de encabezado en una regla.", "task": "Estiliza todos los encabezados consistentemente. Añade color: steelblue al selector agrupado h1, h2, h3.", "previewHTML": "

Main Title

Introduction paragraph with some text.

Section Heading

More content here.

Subsection

Final paragraph.

", "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": "Establece color: steelblue" } ] }, { "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.

.nav a {
color: white;
}

Esto estiliza solo enlaces dentro de .nav, dejando otros enlaces sin cambios.", "task": "Estiliza los enlaces de navegación diferente. Escribe una regla con .nav a como selector y establece color: white.", "previewHTML": "

Read more in our documentation.

", "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 .nav a { (espacio entre .nav y a)" }, { "type": "property_value", "value": { "property": "color", "expected": "white" }, "message": "Establece color: white" } ] }, { "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.

Por ejemplo, los párrafos en una .card podrían ser más pequeños que los párrafos en un article.", "task": "Haz los párrafos dentro de la tarjeta más pequeños. Escribe una regla con .card p como selector y establece font-size: 0.9rem.", "previewHTML": "

Article Title

This is a regular article paragraph with normal-sized text for comfortable reading.

Quick Tip

Card paragraphs should be slightly smaller to fit the compact design.

Back to regular article text here.

", "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 .card p { (espacio entre .card y p)" }, { "type": "property_value", "value": { "property": "font-size", "expected": "0.9rem" }, "message": "Establece font-size: 0.9rem" } ] } ] }