{ "$schema": "../../schemas/code-crispies-module-schema.json", "id": "units-variables", "title": "Одиниці CSS та змінні", "description": "Зрозумійте різноманітність одиниць вимірювання CSS та як визначати й використовувати кастомні властивості для стилів, які легко підтримувати.", "difficulty": "beginner", "lessons": [ { "id": "units-1", "title": "Relative Units", "description": "CSS пропонує два типи одиниць: абсолютні (як px) та відносні (як % і rem). Відносні одиниці адаптуються до контексту, роблячи макети гнучкими та доступними.

Поширені відносні одиниці:
% – Відносно батьківського елемента
rem – Відносно кореневого розміру шрифту (зазвичай 16px)
em – Відносно розміру шрифту елемента

Поширений патерн для читабельного контенту: встановіть width: 100%, щоб заповнити доступний простір, потім max-width: 40rem для обмеження довжини рядка.", "task": "Цей текст статті занадто широкий на великих екранах. Додайте max-width: 40rem для оптимальної ширини читання.", "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": "Встановіть max-width: 40rem" } ] }, { "id": "units-2", "title": "CSS Variables", "description": "Кастомні властивості CSS (змінні) дозволяють визначати значення для повторного використання. Визначайте їх за допомогою --назва та використовуйте з var(--назва). Змінні, визначені на :root, доступні всюди.", "task": "Визначте --brand: steelblue в :root, потім використайте як колір background для .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": "Визначте змінну --brand", "options": { "caseSensitive": false } }, { "type": "contains", "value": "steelblue", "message": "Встановіть значення steelblue", "options": { "caseSensitive": false } } ] }, { "id": "units-3", "title": "calc() Function", "description": "Функція calc() дозволяє змішувати різні одиниці в обчисленнях. Це важливо для макетів, що поєднують фіксовані та гнучкі розміри, як макет із сайдбаром.", "task": "Основний контент повинен заповнити залишок місця після сайдбару 200px. Встановіть width: calc(100% - 200px) на .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": "Встановіть width: calc(100% - 200px)", "options": { "caseSensitive": false } } ] }, { "id": "units-4", "title": "Viewport Units", "description": "Одиниці viewport розміряють елементи відносно вікна браузера:
vw – 1% ширини viewport
vh – 1% висоти viewport

Вони ідеальні для повноекранних секцій як hero-банери.", "task": "Зробіть цю hero-секцію висотою з viewport, встановивши 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": "Встановіть min-height: 100vh" } ] } ] }