{ "$schema": "../../schemas/code-crispies-module-schema.json", "id": "units-variables", "title": "Jednostki CSS i zmienne", "description": "Poznaj różnorodność jednostek miar CSS oraz jak definiować i używać właściwości niestandardowych dla łatwych w utrzymaniu stylów.", "difficulty": "beginner", "lessons": [ { "id": "units-1", "title": "Relative Units", "description": "CSS oferuje dwa typy jednostek: absolutne (jak px) i względne (jak % i rem). Jednostki względne dostosowują się do kontekstu, czyniąc layouty elastycznymi i dostępnymi.

Popularne jednostki względne:
% – Względem elementu nadrzędnego
rem – Względem rozmiaru czcionki root (zwykle 16px)
em – Względem rozmiaru czcionki elementu

Popularny wzorzec dla czytelnej treści: ustaw width: 100%, aby wypełnić dostępną przestrzeń, potem max-width: 40rem aby ograniczyć długość linii dla czytelności.", "task": "Ten tekst artykułu jest zbyt szeroki na dużych ekranach. Dodaj max-width: 40rem dla optymalnej szerokości czytania.", "previewHTML": "

The Art of Typography

Good typography is invisible. When text is set well, readers absorb information without noticing the design decisions that make it comfortable to read. Line length is crucial—too wide and eyes get lost, too narrow and reading becomes choppy.

The ideal line length is 45-75 characters per line. At typical font sizes, this works out to roughly 40rem maximum width.

", "previewBaseCSS": "body { font-family: Georgia, serif; padding: 1rem; background: #f9f9f9; } .article { background: white; padding: 2rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); } .article h2 { margin: 0 0 1rem; color: #333; } .article p { margin: 0 0 1rem; line-height: 1.6; color: #444; } .article p:last-child { margin-bottom: 0; }", "sandboxCSS": "", "codePrefix": ".article {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "max-width: 40rem;", "previewContainer": "preview-area", "validations": [ { "type": "property_value", "value": { "property": "max-width", "expected": "40rem" }, "message": "Ustaw max-width: 40rem" } ] }, { "id": "units-2", "title": "CSS Variables", "description": "Właściwości niestandardowe CSS (zmienne) pozwalają definiować wartości wielokrotnego użytku. Definiuj je za pomocą --nazwa i używaj z var(--nazwa). Zmienne zdefiniowane na :root są dostępne wszędzie.", "task": "Zdefiniuj --brand: steelblue w :root, następnie użyj jako koloru background dla .btn.", "previewHTML": "
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .actions { display: flex; gap: 1rem; } .btn { color: white; border: none; padding: 12px 24px; border-radius: 6px; font-size: 1rem; cursor: pointer; background: #ccc; }", "sandboxCSS": "", "codePrefix": ":root {\n ", "initialCode": "", "codeSuffix": "\n}\n\n.btn {\n background: var(--brand);\n}", "solution": "--brand: steelblue;", "previewContainer": "preview-area", "validations": [ { "type": "contains", "value": "--brand", "message": "Zdefiniuj zmienną --brand", "options": { "caseSensitive": false } }, { "type": "contains", "value": "steelblue", "message": "Ustaw wartość na steelblue", "options": { "caseSensitive": false } } ] }, { "id": "units-3", "title": "calc() Function", "description": "Funkcja calc() pozwala mieszać różne jednostki w obliczeniach. Jest niezbędna dla layoutów łączących stałe i elastyczne rozmiary, jak układ z sidebar.", "task": "Główna treść powinna wypełnić pozostałe miejsce po sidebarze 200px. Ustaw width: calc(100% - 200px) na .main.", "previewHTML": "

Main Content

This area should fill the remaining width after accounting for the fixed-width sidebar.

", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .layout { display: flex; gap: 1rem; } .sidebar { width: 200px; background: #1a1a2e; color: white; padding: 1rem; border-radius: 8px; flex-shrink: 0; } .main { background: white; padding: 1rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .main h2 { margin: 0 0 8px; } .main p { margin: 0; color: #666; }", "sandboxCSS": "", "codePrefix": ".main {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "width: calc(100% - 200px);", "previewContainer": "preview-area", "validations": [ { "type": "regex", "value": "width:\\s*calc\\(\\s*100%\\s*-\\s*200px\\s*\\)", "message": "Ustaw width: calc(100% - 200px)", "options": { "caseSensitive": false } } ] }, { "id": "units-4", "title": "Viewport Units", "description": "Jednostki viewport wymiarują elementy względem okna przeglądarki:
vw – 1% szerokości viewport
vh – 1% wysokości viewport

Są idealne dla sekcji pełnoekranowych jak banery hero.", "task": "Spraw, aby ta sekcja hero wypełniła wysokość viewport ustawiając min-height: 100vh.", "previewHTML": "

Welcome

Scroll down to explore

", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .hero { background: linear-gradient(135deg, #1a1a2e 0%, steelblue 100%); color: white; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 2rem; } .hero h1 { margin: 0 0 1rem; font-size: 2.5rem; } .hero p { margin: 0; opacity: 0.8; }", "sandboxCSS": "", "codePrefix": ".hero {\n ", "initialCode": "", "codeSuffix": "\n}", "solution": "min-height: 100vh;", "previewContainer": "preview-area", "validations": [ { "type": "property_value", "value": { "property": "min-height", "expected": "100vh" }, "message": "Ustaw min-height: 100vh" } ] } ] }