{ "$schema": "../../schemas/code-crispies-module-schema.json", "id": "flexbox", "title": "CSS Flexbox", "description": "Domina el modelo de caja flexible para diseños responsivos modernos", "difficulty": "intermediate", "lessons": [ { "id": "flexbox-1", "title": "Container", "description": "Antes de flexbox, incluso los diseños simples requerían floats, hacks de posicionamiento o diseños basados en tablas. Flexbox (Flexible Box Layout) revolucionó CSS al proporcionar un sistema de diseño unidimensional diseñado específicamente para distribuir espacio y alinear contenido.

Cómo funciona: Cuando estableces display: flex en un elemento, se convierte en un contenedor flex. Sus hijos directos automáticamente se convierten en elementos flex que fluyen a lo largo de un eje principal (horizontal por defecto). Esta única propiedad transforma elementos de bloque apilados en una fila horizontal.

Los dos ejes:
Eje principal – La dirección primaria del flujo de elementos (row = izquierda→derecha)
Eje transversal – Perpendicular al principal (row = arriba→abajo)

.nav {\n  display: flex;\n}
", "task": "Este menú de navegación se apila verticalmente. Añade display: flex para organizar los enlaces horizontalmente.", "previewHTML": "", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .nav { background: #1a1a2e; padding: 1rem; } .nav a { color: white; text-decoration: none; padding: 8px 1rem; border-radius: 4px; } .nav a:hover { background: rgba(255,255,255,0.1); }", "sandboxCSS": "", "codePrefix": ".nav {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "display: flex;", "previewContainer": "preview-area", "validations": [ { "type": "property_value", "value": { "property": "display", "expected": "flex" }, "message": "Establece display: flex" } ] }, { "id": "flexbox-2", "title": "Gap", "description": "La propiedad gap añade espaciado consistente entre elementos flex sin necesidad de márgenes. Solo crea espacio entre elementos, no en los bordes.", "task": "Añade gap: 1rem para espaciar uniformemente los enlaces de navegación.", "previewHTML": "", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .nav { background: #1a1a2e; padding: 1rem; display: flex; } .nav a { color: white; text-decoration: none; padding: 8px 1rem; border-radius: 4px; background: rgba(255,255,255,0.1); }", "sandboxCSS": "", "codePrefix": ".nav {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "gap: 1rem;", "previewContainer": "preview-area", "validations": [ { "type": "property_value", "value": { "property": "gap", "expected": "1rem" }, "message": "Establece gap: 1rem" } ] }, { "id": "flexbox-3", "title": "Justify Content", "description": "justify-content distribuye elementos a lo largo del eje principal. Valores comunes:
flex-start – agrupar al inicio
flex-end – agrupar al final
center – centrar elementos
space-between – espacio igual entre elementos
space-around – espacio igual alrededor de elementos", "task": "Empuja el botón \"Login\" hacia la derecha estableciendo justify-content: space-between en la navegación.", "previewHTML": "", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .nav { background: #1a1a2e; padding: 1rem; display: flex; } .links { display: flex; gap: 8px; } .nav a { color: white; text-decoration: none; padding: 8px 1rem; border-radius: 4px; } .nav a:hover { background: rgba(255,255,255,0.1); } .login { background: steelblue; }", "sandboxCSS": "", "codePrefix": ".nav {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "justify-content: space-between;", "previewContainer": "preview-area", "validations": [ { "type": "property_value", "value": { "property": "justify-content", "expected": "space-between" }, "message": "Establece justify-content: space-between" } ] }, { "id": "flexbox-4", "title": "Align Items", "description": "align-items controla la alineación en el eje transversal (vertical cuando flex-direction es row). Los valores incluyen:
stretch – estirar para llenar (por defecto)
flex-start – alinear arriba
flex-end – alinear abajo
center – centrar verticalmente", "task": "El logo y los enlaces de navegación tienen diferentes alturas. Céntralos verticalmente con align-items: center.", "previewHTML": "
ACME
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .header { background: white; padding: 1rem 2rem; display: flex; justify-content: space-between; border-bottom: 1px solid #eee; } .logo { font-size: 1.5rem; font-weight: bold; color: steelblue; } nav { display: flex; gap: 1rem; } nav a { color: #333; text-decoration: none; font-size: 0.9rem; }", "sandboxCSS": "", "codePrefix": ".header {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "align-items: center;", "previewContainer": "preview-area", "validations": [ { "type": "property_value", "value": { "property": "align-items", "expected": "center" }, "message": "Establece align-items: center" } ] }, { "id": "flexbox-5", "title": "Flex Wrap", "description": "Por defecto, los elementos flex se comprimen en una línea. flex-wrap: wrap permite que los elementos fluyan a múltiples líneas cuando se quedan sin espacio.", "task": "Estas tarjetas desbordan el contenedor. Añade flex-wrap: wrap para permitir que pasen a nuevas filas.", "previewHTML": "
Card 1
Card 2
Card 3
Card 4
Card 5
Card 6
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; background: #f5f5f5; } .cards { display: flex; gap: 1rem; } .card { background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); min-width: 120px; text-align: center; }", "sandboxCSS": "", "codePrefix": ".cards {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "flex-wrap: wrap;", "previewContainer": "preview-area", "validations": [ { "type": "property_value", "value": { "property": "flex-wrap", "expected": "wrap" }, "message": "Establece flex-wrap: wrap" } ] }, { "id": "flexbox-6", "title": "Flex Grow", "description": "La propiedad flex en los elementos controla cómo crecen y se encogen. flex: 1 hace que un elemento crezca para llenar el espacio disponible. Múltiples elementos con flex: 1 comparten el espacio equitativamente.", "task": "Haz que el campo de búsqueda se expanda para llenar el espacio disponible estableciendo flex: 1 en .search.", "previewHTML": "
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .toolbar { display: flex; gap: 8px; padding: 1rem; background: #f5f5f5; border-radius: 8px; } .search { padding: 8px 1rem; border: 1px solid #ddd; border-radius: 4px; font-size: 1rem; } .btn { padding: 8px 1rem; background: steelblue; color: white; border: none; border-radius: 4px; cursor: pointer; }", "sandboxCSS": "", "codePrefix": ".search {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "flex: 1;", "previewContainer": "preview-area", "validations": [ { "type": "property_value", "value": { "property": "flex", "expected": "1" }, "message": "Establece flex: 1" } ] } ] }