Відкрийте CSS будь-якого сайту, і ви побачите кольори задані як #3b82f6, rgb(59, 130, 246), hsl(217, 91%, 60%) — три різні записи одного й того самого кольору. Навіщо стільки форматів? Чи є серед них «правильний»? І чому дизайнери все частіше кажуть про загадковий oklch()?
Справа в тому, що кожна колірна модель дає різний рівень контролю та інтуїтивності. Hex — компактний, але нечитабельний. HSL — зрозумілий людині, але має проблеми з однаковістю яскравості. OKLCH — вирішує ці проблеми, але поки новий.
У попередній статті ми навчились оформлювати текст — шрифти, розміри, інтервали. Тепер додамо кольори та фони — те, що робить дизайн по-справжньому живим.
Додавання кольору — це не просто «зробити красивіше». Колір передає настрій, керує увагою і забезпечує доступність інтерфейсу.
За стандартами Web Content Accessibility Guidelines (WCAG), текст повинен бути достатньо контрастним відносно фону, щоб його могли читати люди з вадами зору.
4.5:1 для звичайного тексту та 3:1 для великого тексту (від 18pt або 14pt bold).7:1 для звичайного тексту та 4.5:1 для великого.У веб-дизайні часто використовується правило пропорції кольорів:
Користувачі звикли до певних паттернів:
color (Колір тексту)Перед тим як розбирати колірні моделі, почнемо з найпростішого — властивості color. Вона задає колір тексту для елемента.
<div class="color-demo-text">
<p class="text-primary">Цей текст має основний колір.</p>
<p class="text-error">Цей текст свідчить про помилку!</p>
<p class="text-muted">Цей текст є менш важливим (приглушеним).</p>
</div>
.color-demo-text {
font-family: system-ui, sans-serif;
font-size: 1rem;
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 8px;
background: white;
}
.text-primary {
color: #2563eb; /* Синій */
font-weight: 600;
}
.text-error {
color: #dc2626; /* Червоний */
}
.text-muted {
color: #64748b; /* Сірий */
}
p {
color: #333333;
}
Властивість color успадковується (inherited). Це означає, що якщо ви задасте колір для <body>, всі текстові елементи всередині (заголовки, параграфи) отримають цей колір, якщо не мають свого власного.
body {
color: #1e293b; /* Задає колір для всього тексту на сторінці */
}
currentColorcurrentColor — це спеціальне ключове слово, яке приймає значення поточної властивості color елемента. Воно вкрай корисне для рамок, тіней або SVG-іконок. Якщо ви зміните color, всі властивості, що використовують currentColor, автоматично оновляться:
<div class="current-color-demo">
<button class="btn btn-blue">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" width="20" height="20">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
Підтвердити
</button>
<button class="btn btn-red">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" width="20" height="20">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
Видалити
</button>
</div>
.current-color-demo {
display: flex;
gap: 1rem;
font-family: system-ui, sans-serif;
}
.btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
font-size: 0.9rem;
font-weight: 600;
background: transparent;
border: 2px solid currentColor; /* Рамка бере колір тексту */
border-radius: 6px;
cursor: pointer;
}
.btn-blue {
color: #2563eb; /* Текст, рамка та іконка стають синіми */
}
.btn-red {
color: #dc2626; /* Текст, рамка та іконка стають червоними */
}
.alert {
color: #dc2626;
border: 1px solid currentColor; /* Рамка буде #dc2626 */
box-shadow: 0 4px 6px currentColor; /* Тінь теж #dc2626 */
}
CSS має 148 вбудованих кольорів із текстовими іменами:
<div class="color-grid">
<div class="swatch" style="background-color: tomato;">tomato</div>
<div class="swatch" style="background-color: steelblue;">steelblue</div>
<div class="swatch" style="background-color: gold;">gold</div>
<div class="swatch" style="background-color: mediumseagreen;">mediumseagreen</div>
<div class="swatch" style="background-color: slateblue;">slateblue</div>
<div class="swatch" style="background-color: coral;">coral</div>
<div class="swatch" style="background-color: darkcyan;">darkcyan</div>
<div class="swatch" style="background-color: hotpink;">hotpink</div>
</div>
.color-grid {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
font-family: system-ui, sans-serif;
}
.swatch {
padding: 0.75rem 1rem;
border-radius: 6px;
font-size: 0.8rem;
color: white;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
Іменовані кольори зручні для прототипування, але не підходять для точного дизайну — ви обмежені 148 варіантами без можливості тонкого налаштування.
Найпопулярніший формат у CSS. Записується як #RRGGBB. Насправді це просто запис моделі RGB, але у шістнадцятковій (hexadecimal) системі числення (Base16). Кожна пара символів представляє градацію від 00 (мінімальна інтенсивність, 0 у десятковій системі) до FF (максимальна інтенсивність, 255 у десятковій).
Тобто #FF0000 означає максимум червоного і нуль зеленого та синього. #FFFFFF — коли всі три канали світяться на максимум, ми отримуємо білий. #000000 — відсутність світла, тобто чорний.
<div class="color-demo-grid">
<div class="swatch-box hex-element">
<strong>.element</strong>
<p>Повний запис HEX</p>
</div>
<div class="swatch-box hex-short">
<strong>.short</strong>
<p>Скорочений запис</p>
</div>
<div class="swatch-box hex-transparent">
<strong>.transparent</strong>
<p>Напівпрозорий (50%)</p>
</div>
</div>
.color-demo-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
font-family: system-ui, sans-serif;
text-align: center;
}
.swatch-box {
padding: 1.5rem 1rem;
border-radius: 8px;
border: 4px solid transparent;
}
.swatch-box strong { display: block; font-size: 1.1rem; margin-bottom: 0.5rem; }
.swatch-box p { margin: 0; font-size: 0.85rem; opacity: 0.9; }
.hex-element {
color: #1e40af; /* Повний запис */
background: #3b82f6; /* Інший синій */
border-color: #e2e8f0; /* Світло-сірий */
}
/* Скорочений запис — коли пари повторюються */
.hex-short {
color: #fff; /* = #ffffff — білий */
background: #333; /* = #333333 — темно-сірий */
}
/* HEX з прозорістю (8 символів) */
.hex-transparent {
color: #1e40af;
background: #3b82f680; /* Останні 2 символи = alpha (50%) */
border-color: #bfdbfe;
}
#3b82f6 = R:59, G:130, B:246. Перевага — компактність. Недолік — неможливо «на око» зрозуміти, який це колір.Те саме, що HEX, але у десятковому записі — кожен канал від 0 до 255.
Як це працює фізично? Екрани пристроїв використовують адитивну колірну модель (Additive Color Mixing). Уявіть три ліхтарики (червоний, зелений, синій), що світять у темній кімнаті на одну точку. Якщо змішати їх усі на максимум
rgb(255, 255, 255), ми отримаємо чисте біле світло. В свою чергуrgb(0, 0, 0)означає, що всі ліхтарики вимкнені (екран чорний). Це кардинально відрізняється від малювання фарбами на папері (субтрактивна модель CMYK), де змішування всіх кольорів створювало б брудно-чорний.
<div class="color-demo-grid bg-pattern">
<div class="swatch-box rgb-element">
<strong>rgb()</strong>
<p>Класичний синтаксис</p>
</div>
<div class="swatch-box rgb-overlay">
<strong>rgba()</strong>
<p>З прозорістю 50%</p>
</div>
<div class="swatch-box rgb-modern">
<strong>Сучасний rgb()</strong>
<p>Через пробіл та /</p>
</div>
</div>
.bg-pattern {
background: repeating-linear-gradient(45deg, #f8fafc, #f8fafc 10px, #e2e8f0 10px, #e2e8f0 20px);
padding: 1rem;
border-radius: 8px;
}
.color-demo-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
font-family: system-ui, sans-serif;
text-align: center;
}
.swatch-box { padding: 1.5rem 1rem; border-radius: 8px; }
.swatch-box strong { display: block; font-size: 1.1rem; margin-bottom: 0.5rem; }
.swatch-box p { margin: 0; font-size: 0.85rem; }
.rgb-element {
color: rgb(30, 64, 175); /* Синій */
background: rgb(59, 130, 246); /* Яскравий синій */
}
/* З прозорістю — четвертий параметр від 0 до 1 */
.rgb-overlay {
color: white;
background: rgba(0, 0, 0, 0.5); /* Напівпрозорий чорний */
}
/* Сучасний синтаксис (без ком, / для alpha) */
.rgb-modern {
color: rgb(30 64 175);
background: rgb(59 130 246 / 0.5);
}
HSL (Hue, Saturation, Lightness) — колірна модель, яка створена спеціально для того, щоб бути інтуїтивно зрозумілою людині. Замість того, щоб вгадувати "скільки червоного і синього треба змішати для отримання рожевого", ми мислимо категоріями художника:
0° (повний оберт 360°) — червоний, 120° — зелений, 240° — синій. Будь-що між ними — плавний перехід.100% — це максимально яскравий, кричущий варіант червоного чи синього. Якщо ми зменшуємо насиченість ближче до 0%, ми ніби "вимиваємо" колір, перетворюючи його на тьмяно-сірий.50% — це оригінальний чистий колір без домішок. Якщо зменшувати до 0%, колір темнішає аж до глухого чорного. Збільшуючи до 100% — ми перетворюємо його на чистий білий.<div class="hsl-demo">
<h4>Відтінок (Hue) — обертання по колірному колу:</h4>
<div class="hue-row">
<div class="swatch" style="background: hsl(0, 80%, 55%);">0° Червоний</div>
<div class="swatch" style="background: hsl(30, 80%, 55%);">30° Оранж</div>
<div class="swatch" style="background: hsl(60, 80%, 50%);">60° Жовтий</div>
<div class="swatch" style="background: hsl(120, 80%, 40%);">120° Зелений</div>
<div class="swatch" style="background: hsl(210, 80%, 55%);">210° Синій</div>
<div class="swatch" style="background: hsl(270, 80%, 55%);">270° Фіолет</div>
</div>
<h4>Насиченість (Saturation) — від сірого до яскравого:</h4>
<div class="hue-row">
<div class="swatch" style="background: hsl(210, 0%, 55%);">0%</div>
<div class="swatch" style="background: hsl(210, 25%, 55%);">25%</div>
<div class="swatch" style="background: hsl(210, 50%, 55%);">50%</div>
<div class="swatch" style="background: hsl(210, 75%, 55%);">75%</div>
<div class="swatch" style="background: hsl(210, 100%, 55%);">100%</div>
</div>
<h4>Яскравість (Lightness) — від чорного до білого:</h4>
<div class="hue-row">
<div class="swatch" style="background: hsl(210, 80%, 10%);color:#fff;">10%</div>
<div class="swatch" style="background: hsl(210, 80%, 30%);color:#fff;">30%</div>
<div class="swatch" style="background: hsl(210, 80%, 50%);">50%</div>
<div class="swatch" style="background: hsl(210, 80%, 70%);">70%</div>
<div class="swatch" style="background: hsl(210, 80%, 90%);color:#333;">90%</div>
</div>
</div>
.hsl-demo {
font-family: system-ui, sans-serif;
font-size: 0.85rem;
color: #1e293b;
}
.hsl-demo h4 {
margin: 0.75rem 0 0.25rem;
font-size: 0.85rem;
}
.hue-row {
display: flex;
gap: 0.25rem;
flex-wrap: wrap;
}
.swatch {
padding: 0.5rem 0.6rem;
border-radius: 6px;
color: white;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
font-size: 0.75rem;
text-align: center;
}
<div class="color-demo-grid bg-pattern">
<div class="swatch-box hsl-element">
<strong>hsl()</strong>
<p>Легко змінити яскравість (рамка нижче)</p>
</div>
<div class="swatch-box hsl-overlay">
<strong>hsla()</strong>
<p>З прозорістю</p>
</div>
</div>
.color-demo-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
font-family: system-ui, sans-serif;
text-align: center;
}
.bg-pattern {
background: repeating-linear-gradient(45deg, #f8fafc, #f8fafc 10px, #e2e8f0 10px, #e2e8f0 20px);
padding: 1rem;
border-radius: 8px;
}
.swatch-box { padding: 1.5rem 1rem; border-radius: 8px; }
.swatch-box strong { margin-bottom: 0.5rem; display: block; font-size: 1.1rem; }
.swatch-box p { margin: 0; font-size: 0.85rem; }
.hsl-element {
color: white;
background: hsl(217, 91%, 60%); /* Основний синій */
border: 4px solid hsl(217, 91%, 40%); /* Темніший варіант — лише L змінено */
}
/* З прозорістю */
.hsl-overlay {
color: white;
background: hsla(0, 0%, 0%, 0.5); /* Напівпрозорий чорний */
/* або сучасний синтаксис */
/* background: hsl(0 0% 0% / 0.5); */
}
L (Lightness). Потрібен пастельний? Зменшіть S (Saturation) і збільшіть L. Потрібен прозорий? Додайте alpha. З HEX-кодами такі маніпуляції «на льоту» — неможливі.oklch() — найновіша колірна модель у CSS, заснована на просторі кольорів Oklab. Вона вирішує головну проблему HSL: перцептивну нерівномірність.
Людське око біологічно сприймає різні кольори з різною інтенсивністю (наприклад, жовтий здається людському оку природно "світлішим" за синій). У HSL, якщо ви поставите однакову світлоту L: 50% для жовтого hsl(60, 100%, 50%) та синього hsl(240, 100%, 50%) — жовтий буде різати око, а синій здаватиметься занадто темним. OKLCH виправляє це завдяки математичній моделі, що імітує людський зір. Якщо ви фіксуєте яскравість (Lightness) в OKLCH, усі генеровані кольори виглядатимуть абсолютно однаково яскравими, дозволяючи програмно генерувати ідеально збалансовані та доступні колірні палітри без ручного підганяння.
<div class="color-demo-grid bg-pattern">
<div class="swatch-box oklch-element">
<strong>oklch()</strong>
<p>Рівномірна яскравість</p>
</div>
<div class="swatch-box oklch-transparent">
<strong>З прозорістю</strong>
<p>oklch(... / 0.5)</p>
</div>
</div>
.color-demo-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
font-family: system-ui, sans-serif;
text-align: center;
}
.bg-pattern {
background: repeating-linear-gradient(45deg, #f8fafc, #f8fafc 10px, #e2e8f0 10px, #e2e8f0 20px);
padding: 1rem;
border-radius: 8px;
}
.swatch-box { padding: 1.5rem 1rem; border-radius: 8px; }
.swatch-box strong { margin-bottom: 0.5rem; display: block; font-size: 1.1rem; }
.swatch-box p { margin: 0; font-size: 0.85rem; }
.oklch-element {
/* oklch(Lightness Chroma Hue) */
color: oklch(0.55 0.2 250); /* Синій */
background: oklch(0.95 0.05 250); /* Дуже світлий синій */
}
/* З прозорістю */
.oklch-transparent {
color: white;
background: oklch(0.55 0.2 250 / 0.5);
}
0 (чорний) до 1 (білий). На відміну від HSL, яскравість перцептивно однакова для різних відтінків.0 = сірий, 0.4 = максимально яскравий. Залежить від відтінку та дисплея.| Формат | Приклад | Інтуїтивність | Маніпуляції | Підтримка |
|---|---|---|---|---|
| Named | steelblue | ⭐⭐⭐ | ❌ | ✅ |
| HEX | #4682b4 | ⭐ | ❌ | ✅ |
| RGB | rgb(70, 130, 180) | ⭐⭐ | ❌ | ✅ |
| HSL | hsl(207, 44%, 49%) | ⭐⭐⭐ | ✅ | ✅ |
| OKLCH | oklch(0.57 0.1 240) | ⭐⭐⭐ | ✅✅ | ✅ (сучасні) |
Замість хардкоду кольорів по всьому CSS, створіть систему через змінні:
:root {
/* Основна палітра */
--color-primary: hsl(217, 91%, 60%);
--color-primary-light: hsl(217, 91%, 75%);
--color-primary-dark: hsl(217, 91%, 40%);
/* Нейтральні */
--color-gray-50: hsl(210, 40%, 98%);
--color-gray-100: hsl(210, 40%, 96%);
--color-gray-200: hsl(214, 32%, 91%);
--color-gray-500: hsl(215, 16%, 47%);
--color-gray-700: hsl(215, 25%, 27%);
--color-gray-900: hsl(222, 47%, 11%);
/* Семантичні кольори */
--color-success: hsl(142, 71%, 45%);
--color-warning: hsl(38, 92%, 50%);
--color-error: hsl(0, 84%, 60%);
/* Текст та фон */
--color-text: var(--color-gray-900);
--color-text-muted: var(--color-gray-500);
--color-bg: white;
--color-bg-secondary: var(--color-gray-50);
--color-border: var(--color-gray-200);
}
Використання:
<div class="var-demo">
<div class="var-body">
<p>Текст у body</p>
<button class="btn-primary">.btn-primary</button>
<div class="alert-error">.alert-error</div>
</div>
</div>
.var-demo {
/* Симуляція :root */
--color-primary: hsl(217, 91%, 60%);
--color-primary-dark: hsl(217, 91%, 40%);
--color-error: hsl(0, 84%, 60%);
--color-text: hsl(222, 47%, 11%);
--color-bg: white;
font-family: system-ui, sans-serif;
}
.var-body {
color: var(--color-text);
background-color: var(--color-bg);
padding: 1.5rem;
border-radius: 8px;
border: 1px solid #e2e8f0;
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
align-items: center;
}
.var-body p { margin: 0; font-weight: 500; }
.btn-primary {
background-color: var(--color-primary);
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 6px;
cursor: pointer;
font-family: inherit;
font-weight: 500;
transition: background-color 0.2s;
}
.btn-primary:hover {
background-color: var(--color-primary-dark);
}
.alert-error {
color: var(--color-error);
border: 1px solid var(--color-error);
padding: 0.5rem 1rem;
border-radius: 6px;
background-color: hsl(0, 84%, 98%);
}
body {
color: var(--color-text);
background-color: var(--color-bg);
}
.btn-primary {
background-color: var(--color-primary);
color: white;
}
.btn-primary:hover {
background-color: var(--color-primary-dark);
}
.alert-error {
color: var(--color-error);
border: 1px solid var(--color-error);
}
hsl(217, 91%, 60%), ви автоматично отримуєте всю палітру — просто змінюючи L для відтінків (light/dark) та S для пастельних варіантів. HEX не дає такої гнучкості.prefers-color-schemeCSS дозволяє автоматично перемикати кольори відповідно до системних налаштувань користувача:
/* Світла тема — за замовчуванням */
:root {
--color-text: hsl(222, 47%, 11%);
--color-bg: hsl(0, 0%, 100%);
--color-bg-secondary: hsl(210, 40%, 98%);
--color-border: hsl(214, 32%, 91%);
--color-primary: hsl(217, 91%, 60%);
}
/* Темна тема — автоматично */
@media (prefers-color-scheme: dark) {
:root {
--color-text: hsl(210, 40%, 96%);
--color-bg: hsl(222, 47%, 11%);
--color-bg-secondary: hsl(217, 33%, 17%);
--color-border: hsl(215, 25%, 27%);
--color-primary: hsl(217, 91%, 70%);
}
}
<div class="theme-demo">
<div class="card-light">
<h3>☀️ Світла тема</h3>
<p>Темний текст на світлому фоні — класичний варіант.</p>
<button class="btn-light">Кнопка</button>
</div>
<div class="card-dark">
<h3>🌙 Темна тема</h3>
<p>Світлий текст на темному фоні — менше навантаження на око.</p>
<button class="btn-dark">Кнопка</button>
</div>
</div>
.theme-demo {
display: flex;
gap: 1rem;
font-family: system-ui, sans-serif;
font-size: 0.9rem;
}
.card-light {
flex: 1;
padding: 1.5rem;
border-radius: 12px;
background-color: #ffffff;
color: #1e293b;
border: 1px solid #e2e8f0;
}
.card-dark {
flex: 1;
padding: 1.5rem;
border-radius: 12px;
background-color: #0f172a;
color: #e2e8f0;
border: 1px solid #334155;
}
.card-light h3,
.card-dark h3 {
margin: 0 0 0.5rem;
font-size: 1.1rem;
}
.card-light p,
.card-dark p {
margin: 0 0 1rem;
line-height: 1.5;
}
.btn-light {
padding: 0.5rem 1.5rem;
background-color: #3b82f6;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-family: inherit;
}
.btn-dark {
padding: 0.5rem 1.5rem;
background-color: #60a5fa;
color: #0f172a;
border: none;
border-radius: 6px;
cursor: pointer;
font-family: inherit;
}
prefers-color-scheme — це медіа-запит, що зчитує налаштування теми у системних параметрах (Windows, macOS, Android, iOS). Перевизначення змінних у :root — і весь сайт автоматично перемикає тему без жодного JavaScript. Детальніше про медіа-запити — у статті про адаптивний дизайн.background-colorЗадає суцільний колір фону:
<div class="color-demo-grid bg-pattern">
<div class="swatch-box bg-hex">#f8fafc</div>
<div class="swatch-box bg-hsl">hsl(...)</div>
<div class="swatch-box bg-transparent">transparent</div>
</div>
.color-demo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); gap: 1rem; font-family: system-ui, sans-serif; text-align: center; }
.bg-pattern { background: repeating-linear-gradient(45deg, #e2e8f0, #e2e8f0 10px, #cbd5e1 10px, #cbd5e1 20px); padding: 1rem; border-radius: 8px; }
.swatch-box { padding: 1.5rem 1rem; border-radius: 8px; border: 1px solid #94a3b8; font-weight: 600; color: #1e293b; }
.bg-hex { background-color: #f8fafc; }
.bg-hsl { background-color: hsl(210, 40%, 98%); }
.bg-transparent { background-color: transparent; }
.element {
background-color: #f8fafc;
background-color: hsl(210, 40%, 98%);
background-color: transparent; /* Прозорий — значення за замовчуванням */
}
background-imageФонове зображення — від файлів до градієнтів:
<div class="hero-bg-preview">
Фонове зображення
</div>
.hero-bg-preview {
height: 150px;
border-radius: 8px;
background-color: #e2e8f0;
/* Тут ми використаємо градієнт замість реального фото для демо */
background-image: linear-gradient(45deg, #3b82f6, #ec4899);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-family: system-ui, sans-serif;
font-weight: bold;
font-size: 1.2rem;
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
}
.hero {
background-image: url('/images/hero-bg.jpg');
}
background-sizeЯк масштабувати фонове зображення:
<div class="bg-demo-row">
<div class="bg-box" style="background-size: cover;">
<span>cover</span>
</div>
<div class="bg-box" style="background-size: contain;">
<span>contain</span>
</div>
<div class="bg-box" style="background-size: 100% 100%;">
<span>100% 100%</span>
</div>
</div>
.bg-demo-row {
display: flex;
gap: 0.75rem;
font-family: system-ui, sans-serif;
}
.bg-box {
width: 150px;
height: 100px;
border: 2px solid #e2e8f0;
border-radius: 8px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='60' viewBox='0 0 80 60'%3E%3Crect fill='%233b82f6' width='80' height='60' rx='4'/%3E%3Ctext x='40' y='35' text-anchor='middle' fill='white' font-size='12' font-family='sans-serif'%3EIMG%3C/text%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
display: flex;
align-items: flex-end;
justify-content: center;
padding-bottom: 0.25rem;
}
.bg-box span {
font-size: 0.7rem;
color: #64748b;
background: rgba(255, 255, 255, 0.8);
padding: 0.1rem 0.3rem;
border-radius: 3px;
}
| Значення | Поведінка |
|---|---|
cover | Масштабує так, щоб покрити весь контейнер (може обрізатися) |
contain | Масштабує так, щоб вміститися повністю (можуть бути порожні зони) |
100% 100% | Розтягує точно до розмірів контейнера (може спотворити пропорції) |
200px 150px | Точний розмір у пікселях |
auto | Оригінальний розмір зображення |
background-positionДе розмістити фон усередині елемента:
<div class="bg-demo-grid">
<div class="pos-box pos-center"><span>center</span></div>
<div class="pos-box pos-top-right"><span>top right</span></div>
<div class="pos-box pos-percent"><span>50% 30%</span></div>
<div class="pos-box pos-px"><span>20px 10px</span></div>
</div>
.bg-demo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 1rem; font-family: system-ui, sans-serif; text-align: center; margin-bottom: 1.5rem; }
.pos-box {
margin-top: 0.5rem;
height: 100px; border-radius: 8px; border: 2px solid #e2e8f0;
background-image: radial-gradient(circle at center, #3b82f6 30%, transparent 31%);
background-size: 30px 30px;
background-repeat: no-repeat;
background-color: #f8fafc;
position: relative;
}
.pos-box span { position: absolute; bottom: -1.75rem; left: 0; right: 0; font-size: 0.8rem; color: #64748b; }
.pos-center { background-position: center; }
.pos-top-right { background-position: top right; }
.pos-percent { background-position: 50% 30%; }
.pos-px { background-position: 20px 10px; }
.element {
background-position: center; /* По центру */
background-position: top right; /* Верхній правий кут */
background-position: 50% 30%; /* 50% по X, 30% по Y */
background-position: 20px 10px; /* 20px зліва, 10px зверху */
}
background-repeat<div class="rep-demo-grid">
<div class="rep-box rep-repeat"><span>repeat</span></div>
<div class="rep-box rep-no-repeat"><span>no-repeat</span></div>
<div class="rep-box rep-repeat-x"><span>repeat-x</span></div>
<div class="rep-box rep-space"><span>space</span></div>
</div>
.rep-demo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 1rem; font-family: system-ui, sans-serif; text-align: center; margin-bottom: 1.5rem; }
.rep-box {
margin-top: 0.5rem;
height: 100px; border-radius: 8px; border: 2px solid #e2e8f0;
background-image: radial-gradient(circle at center, #3b82f6 30%, transparent 31%);
background-size: 30px 30px;
background-color: #f8fafc;
position: relative;
}
.rep-box span { position: absolute; bottom: -1.75rem; left: 0; right: 0; font-size: 0.8rem; color: #64748b; }
.rep-repeat { background-repeat: repeat; }
.rep-no-repeat { background-repeat: no-repeat; background-position: center; }
.rep-repeat-x { background-repeat: repeat-x; background-position: center; }
.rep-space { background-repeat: space; }
.element {
background-repeat: repeat; /* Повторювати в обидва боки (за замовчуванням) */
background-repeat: no-repeat; /* Не повторювати */
background-repeat: repeat-x; /* Повторювати тільки горизонтально */
background-repeat: repeat-y; /* Повторювати тільки вертикально */
background-repeat: space; /* Повторювати з рівними проміжками */
background-repeat: round; /* Повторювати, масштабуючи до цілого числа */
}
background-attachment<div class="attachment-demo" class="parallax">
<div class="scroll-box">Прокрутіть мене вниз! (Фон зафіксований)</div>
</div>
.attachment-demo {
height: 150px;
overflow-y: scroll;
border-radius: 8px;
background-image: linear-gradient(45deg, #3b82f6, #ec4899);
background-attachment: fixed;
color: white;
font-family: system-ui, sans-serif;
text-align: center;
font-weight: bold;
}
.scroll-box {
height: 300px;
padding-top: 2rem;
}
.parallax {
background-attachment: fixed; /* Фон фіксований — ефект параллаксу */
background-attachment: scroll; /* Фон прокручується разом з елементом (default) */
background-attachment: local; /* Фон прокручується з вмістом елемента */
}
backgroundУсе в одному рядку:
<div class="hero-bg-preview hero-short">
Скорочення background
</div>
.hero-bg-preview {
height: 100px;
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
color: white; font-family: system-ui, sans-serif; font-weight: bold; text-shadow: 0 2px 4px rgba(0,0,0,0.3);
}
.hero-short {
background: #0f172a linear-gradient(45deg, #3b82f680, #ec489980) center/cover no-repeat;
}
.hero {
/* background: color image position/size repeat attachment */
background: #0f172a url('/images/hero.jpg') center/cover no-repeat fixed;
}
backgroundскидає всі невказані властивості до значень за замовчуванням. Якщо до скорочення був background-color: red, а в скороченні колір не вказано — він стане transparent. Будьте обережні при змішуванні скорочення з окремими властивостями.Давайте поєднаємо все вивчене. Спробуйте змінити властивості, щоб побачити, як вони взаємодіють між собою:
<div class="bg-playground">
<div class="bg-controls">
<!-- IMAGE -->
<fieldset class="bg-fieldset" id="fs-image">
<legend>Зображення (image)</legend>
<label><input type="radio" name="bgImg" value="img1" checked> Градієнтне фото</label>
<label><input type="radio" name="bgImg" value="img2"> Абстракція</label>
<label><input type="radio" name="bgImg" value="pat1"> Патерн Dotted</label>
<label><input type="radio" name="bgImg" value="grad1"> Linear Gradient</label>
</fieldset>
<!-- SIZE -->
<fieldset class="bg-fieldset" id="fs-size">
<legend>Розмір (size)</legend>
<label><input type="radio" name="bgSize" value="cover" checked> cover</label>
<label><input type="radio" name="bgSize" value="contain"> contain</label>
<label><input type="radio" name="bgSize" value="auto"> auto</label>
<label><input type="radio" name="bgSize" value="100%"> 100% 100%</label>
<label><input type="radio" name="bgSize" value="50px"> 50px 50px</label>
</fieldset>
<!-- POSITION -->
<fieldset class="bg-fieldset" id="fs-pos">
<legend>Позиція (position)</legend>
<label><input type="radio" name="bgPos" value="center" checked> center</label>
<label><input type="radio" name="bgPos" value="top-left"> top left</label>
<label><input type="radio" name="bgPos" value="bottom-right"> bottom right</label>
<label><input type="radio" name="bgPos" value="custom"> 50% 20%</label>
</fieldset>
<!-- REPEAT -->
<fieldset class="bg-fieldset" id="fs-rep">
<legend>Повторення (repeat)</legend>
<label><input type="radio" name="bgRep" value="no-repeat" checked> no-repeat</label>
<label><input type="radio" name="bgRep" value="repeat"> repeat</label>
<label><input type="radio" name="bgRep" value="space"> space</label>
<label><input type="radio" name="bgRep" value="round"> round</label>
</fieldset>
</div>
<div class="bg-preview-area">
<div class="bg-target-element">
Фоновий контейнер
</div>
</div>
</div>
.bg-playground { display: flex; flex-direction: column; gap: 1.5rem; font-family: system-ui, sans-serif; color: #1e293b; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; padding: 1.5rem; margin: 1.5rem 0; }
.bg-controls { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; }
.bg-fieldset { border: 1px solid #cbd5e1; border-radius: 8px; padding: 0.5rem 0.75rem; display: flex; flex-direction: column; gap: 0.4rem; background: white; margin: 0; min-width: 0; }
.bg-fieldset legend { font-size: 0.85rem; font-weight: 600; color: #475569; padding: 0 0.5rem; }
.bg-fieldset label { font-size: 0.85rem; display: flex; align-items: center; gap: 0.5rem; cursor: pointer; color: #0f172a; margin: 0; }
.bg-fieldset input[type="radio"] { cursor: pointer; margin: 0; }
.bg-preview-area { width: 100%; height: 250px; border-radius: 8px; border: 2px dashed #94a3b8; background-color: #f1f5f9; overflow: hidden; }
.bg-target-element { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; font-size: 1.5rem; font-weight: bold; color: white; text-shadow: 0 2px 4px rgba(0,0,0,0.8); transition: background 0.3s ease;
/* Default Initial State */
background-image: url('https://images.unsplash.com/photo-1557683316-973673baf926?q=80&w=800&auto=format&fit=crop'); background-size: cover; background-position: center; background-repeat: no-repeat;
}
/* Interactivity logic via CSS :has() */
.bg-playground:has(input[name="bgImg"][value="img1"]:checked) .bg-target-element { background-image: url('https://images.unsplash.com/photo-1557683316-973673baf926?q=80&w=800&auto=format&fit=crop'); }
.bg-playground:has(input[name="bgImg"][value="img2"]:checked) .bg-target-element { background-image: url('https://images.unsplash.com/photo-1579546929518-9e396f3cc809?q=80&w=800&auto=format&fit=crop'); }
.bg-playground:has(input[name="bgImg"][value="pat1"]:checked) .bg-target-element { background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%239C92AC' fill-opacity='0.6' fill-rule='evenodd'%3E%3Ccircle cx='3' cy='3' r='3'/%3E%3Ccircle cx='13' cy='13' r='3'/%3E%3C/g%3E%3C/svg%3E"); }
.bg-playground:has(input[name="bgImg"][value="grad1"]:checked) .bg-target-element { background-image: linear-gradient(45deg, #3b82f6, #ec4899); }
.bg-playground:has(input[name="bgSize"][value="cover"]:checked) .bg-target-element { background-size: cover; }
.bg-playground:has(input[name="bgSize"][value="contain"]:checked) .bg-target-element { background-size: contain; }
.bg-playground:has(input[name="bgSize"][value="auto"]:checked) .bg-target-element { background-size: auto; }
.bg-playground:has(input[name="bgSize"][value="100%"]:checked) .bg-target-element { background-size: 100% 100%; }
.bg-playground:has(input[name="bgSize"][value="50px"]:checked) .bg-target-element { background-size: 50px 50px; }
.bg-playground:has(input[name="bgPos"][value="center"]:checked) .bg-target-element { background-position: center; }
.bg-playground:has(input[name="bgPos"][value="top-left"]:checked) .bg-target-element { background-position: top left; }
.bg-playground:has(input[name="bgPos"][value="bottom-right"]:checked) .bg-target-element { background-position: bottom right; }
.bg-playground:has(input[name="bgPos"][value="custom"]:checked) .bg-target-element { background-position: 50% 20%; }
.bg-playground:has(input[name="bgRep"][value="no-repeat"]:checked) .bg-target-element { background-repeat: no-repeat; }
.bg-playground:has(input[name="bgRep"][value="repeat"]:checked) .bg-target-element { background-repeat: repeat; }
.bg-playground:has(input[name="bgRep"][value="space"]:checked) .bg-target-element { background-repeat: space; }
.bg-playground:has(input[name="bgRep"][value="round"]:checked) .bg-target-element { background-repeat: round; }
Градієнти — це плавні переходи між двома або більше кольорами.
Важливо розуміти: під капотом браузер розглядає та малює градієнт як повноцінне згенероване зображення, а не як заливку кольором. Саме тому градієнти завжди задаються через властивість background-image (або скорочення background), а не через background-color. Це дає нам величезну технічну перевагу — до градієнтів можна застосовувати усі властивості, що доступні для звичайних зображень: ми можемо задавати їм розмір (background-size), повторювати їх мов плитку (background-repeat) або маніпулювати їх позицією.
CSS підтримує три типи градієнтів:
linear-gradient() — лінійний градієнт<div class="grad-row">
<div class="grad gradient-to-right"><span>to right</span></div>
<div class="grad gradient-angled"><span>135deg</span></div>
<div class="grad gradient-multi"><span>multi</span></div>
<div class="grad gradient-stripes"><span>stripes</span></div>
</div>
.grad-row { display: flex; gap: 0.75rem; font-family: system-ui, sans-serif; flex-wrap: wrap; }
.grad { flex: 1; min-width: 100px; height: 100px; border-radius: 12px; display: flex; align-items: center; justify-content: center; }
.grad span { color: white; font-size: 0.85rem; font-weight: 600; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); background: rgba(0,0,0,0.2); padding: 0.2rem 0.5rem; border-radius: 4px; }
.gradient-to-right { background: linear-gradient(to right, #3b82f6, #8b5cf6); }
.gradient-angled { background: linear-gradient(135deg, #f59e0b, #ef4444); }
.gradient-multi { background: linear-gradient(to right, #3b82f6 0%, #8b5cf6 50%, #ec4899 100%); }
.gradient-stripes { background: linear-gradient(to right, #3b82f6 0%, #3b82f6 33%, #f59e0b 33%, #f59e0b 66%, #ef4444 66%, #ef4444 100%); }
/* Напрямок + кольори */
.gradient {
background: linear-gradient(to right, #3b82f6, #8b5cf6);
}
/* Кут у градусах */
.angled {
background: linear-gradient(135deg, #f59e0b, #ef4444);
}
/* Кілька кольорів із зупинками */
.multi {
background: linear-gradient(to right, #3b82f6 0%, #8b5cf6 50%, #ec4899 100%);
}
/* Різкий перехід — «смужки» */
.stripes {
background: linear-gradient(to right, #3b82f6 0%, #3b82f6 33%, #f59e0b 33%, #f59e0b 66%, #ef4444 66%, #ef4444 100%);
}
radial-gradient() — радіальний градієнт<div class="grad-row">
<div class="grad radial-circle"><span>circle</span></div>
<div class="grad radial-ellipse"><span>ellipse</span></div>
</div>
.grad-row { display: flex; gap: 0.75rem; font-family: system-ui, sans-serif; }
.grad { flex: 1; height: 120px; border-radius: 12px; display: flex; align-items: center; justify-content: center; background-color: #1e293b; }
.grad span { color: white; font-size: 0.8rem; font-weight: 600; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); background: rgba(0,0,0,0.2); padding: 0.2rem 0.5rem; border-radius: 4px; }
.radial-circle { background: radial-gradient(circle, #3b82f6, #1e293b); }
.radial-ellipse { background: radial-gradient(ellipse at top left, #f59e0b, transparent); }
/* Колове розповсюдження від центру */
.radial {
background: radial-gradient(circle, #3b82f6, #1e293b);
}
/* Еліпс з іншою точкою початку */
.ellipse {
background: radial-gradient(ellipse at top left, #f59e0b, transparent);
}
conic-gradient() — конічний градієнтКольори розповсюджуються по колу навколо центру:
<div class="grad-row">
<div class="grad conic-1">
<span>Rainbow</span>
</div>
<div class="grad conic-2">
<span>Pie Chart</span>
</div>
<div class="grad conic-3">
<span>Color Wheel</span>
</div>
</div>
.grad-row {
display: flex;
gap: 0.75rem;
font-family: system-ui, sans-serif;
}
.grad {
width: 120px;
height: 120px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.grad span {
color: white;
font-size: 0.75rem;
font-weight: 600;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
text-align: center;
}
.conic-1 {
background: conic-gradient(#ef4444, #f59e0b, #10b981, #3b82f6, #8b5cf6, #ef4444);
}
.conic-2 {
background: conic-gradient(#3b82f6 0% 40%, #f59e0b 40% 70%, #10b981 70% 100%);
}
.conic-3 {
background: conic-gradient(
from 90deg,
hsl(0, 80%, 60%),
hsl(60, 80%, 60%),
hsl(120, 80%, 60%),
hsl(180, 80%, 60%),
hsl(240, 80%, 60%),
hsl(300, 80%, 60%),
hsl(360, 80%, 60%)
);
}
conic-gradient() ідеально підходить для створення кругових діаграм (pie charts) та колірних коліс без JavaScript та SVG.CSS дозволяє накладати кілька фонів один на одного:
.hero {
background:
/* Шар 1 (верхній) — градієнт-оверлей */
linear-gradient(to bottom, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.7)),
/* Шар 2 (нижній) — зображення */ url('/images/hero.jpg') center/cover no-repeat;
}
<div class="multi-bg">
<h2>Множинні фони</h2>
<p>Градієнт поверх патерну</p>
</div>
.multi-bg {
padding: 3rem 2rem;
border-radius: 12px;
color: white;
font-family: system-ui, sans-serif;
text-align: center;
background:
linear-gradient(135deg, rgba(59, 130, 246, 0.85), rgba(139, 92, 246, 0.85)),
repeating-linear-gradient(
45deg,
transparent,
transparent 10px,
rgba(255, 255, 255, 0.05) 10px,
rgba(255, 255, 255, 0.05) 20px
);
}
.multi-bg h2 {
margin: 0 0 0.5rem;
font-size: 1.5rem;
}
.multi-bg p {
margin: 0;
opacity: 0.9;
}
opacity vs rgba / hslaЧаста помилка новачків — використання opacity там, де потрібен лише трохи прозорий фон. Хоча обидва підходи роблять елемент прозорим, вони мають принципово різну поведінку та механіку рендерингу (створюючи так званий контекст накладання / Stacking Context):
<div class="opacity-demo">
<div class="box-opacity">
<strong>opacity: 0.5</strong>
<p>Весь елемент напівпрозорий — і текст також!</p>
</div>
<div class="box-rgba">
<strong>rgba() на фоні</strong>
<p>Тільки фон прозорий — текст залишається чітким!</p>
</div>
</div>
.opacity-demo {
display: flex;
gap: 1rem;
font-family: system-ui, sans-serif;
font-size: 0.85rem;
padding: 1rem;
background: repeating-linear-gradient(45deg, #e2e8f0, #e2e8f0 10px, #f1f5f9 10px, #f1f5f9 20px);
border-radius: 8px;
}
.box-opacity {
flex: 1;
padding: 1rem;
background-color: #1e293b;
color: white;
border-radius: 8px;
opacity: 0.5;
}
.box-rgba {
flex: 1;
padding: 1rem;
background-color: rgba(30, 41, 59, 0.5);
color: white;
border-radius: 8px;
}
.box-opacity strong,
.box-rgba strong {
display: block;
margin-bottom: 0.25rem;
}
.box-opacity p,
.box-rgba p {
margin: 0;
line-height: 1.4;
}
opacity впливає на весь елемент загалом разом з усіма його дочірніми елементами. Браузер спочатку рендерить весь HTML-блок обгортки у пам'яті як єдину плоску "картинку" (включаючи текст, вкладені зображення, рамки), а вже потім робить цю фінальну картинку напівпрозорою. Через це неможливо зробити обгортку напівпрозорою через opacity, а оригінальний текст всередині неї залишити 100% непрозорим. Значення задається від 0 (повністю прозорий) до 1 (непрозорий).Якщо вам потрібен напівпрозорий лише фон (щоб текст залишався чітким та контрастним) — завжди використовуйте прозорість на рівні кольору (Альфа-канал): rgba(), hsla() або oklch(... / alpha) для властивості background-color.Створіть HTML-сторінку з 6 кольоровими блоками. Задайте кольори трьома різними форматами:
Один блок у кожній парі повинен мати прозорість 50%.
Створіть 4 кнопки з різними градієнтами:
:hover-ефектом — при наведенні градієнт «обертається» (змініть напрямок)Створіть два блоки з текстом на смугастому фоні:
opacity: 0.5background-color: rgba(...) та opacity: 1Поясніть, чому текст у першому блоці теж прозорий, а в другому — ні.
Створіть систему кольорів через CSS Custom Properties:
--hue: 217L у hsl(): --color-50, --color-200, --color-500, --color-700, --color-900Бонус: Додайте другу палітру, змінивши лише --hue.
Створіть hero-блок на повну ширину:
backgroundlinear-gradient з rgba)background-size: cover, background-position: centerСтворіть кругову діаграму за допомогою conic-gradient():
border-radius: 50%)Реалізуйте повну систему двох тем:
:root (текст, фон, primary, border, muted)@media (prefers-color-scheme: dark)Тестувйте: у Chrome DevTools → Ctrl + Shift + P → «Emulate CSS prefers-color-scheme: dark».
Створіть лендінг-сторінку, де:
repeating-linear-gradient)hover-анімацієюВикористайте лише CSS — без зображень. Всі кольори — через CSS-змінні.
🎨 Колірні моделі
🖼️ Фони
background об'єднує color, image, position, size, repeat. Множинні фони через кому. Градієнти (linear, radial, conic) — замість зображень.🌗 Теми
prefers-color-scheme = автоматична темна тема без JavaScript. Визначайте кольори через HSL-змінні для легкої зміни палітри.👁️ Прозорість
opacity — весь елемент прозорий (з дітьми). rgba()/hsla() — тільки конкретний колір. Для фонових оверлеїв — завжди rgba.Типографіка в CSS. Шрифти та текст
Глибоке занурення у CSS-типографіку: font-family, @font-face, Google Fonts, font-size (px/em/rem), line-height, text-align, text-decoration, text-overflow, одиниці виміру та CSS Custom Properties для системи типографіки.
Тіні та фільтри в CSS
Повний гід по box-shadow, text-shadow, filter та backdrop-filter. Анатомія тіней, шарування, inset-тіні, drop-shadow для SVG, blur, brightness, contrast, glassmorphism. Продуктивність і best practices.