Урок 06. Теория: ступени, OKLCH, контраст

📁 Раздел: Базовые утилиты ⏱️ Время изучения: ~45 мин 🎯 Сложность: Начальная

⚡ Кратко

Ступень отвечает за светлоту: 50–200 — фоны, 300–400 — рамки и разделители, 500–600 — акценты и заливки кнопок, 700–950 — текст. Пара «фон 100 / текст 800» из одного оттенка почти всегда даёт хороший контраст. Прозрачность пишется дробью, а сам цвет хранится в OKLCH — поэтому ступени выглядят равномерно.

Как устроена палитра

В палитре 22 оттенка: нейтральные (slate, gray, zinc, neutral, stone) и цветные — от red до rose. У каждого 11 ступеней: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950.

50
100
200
300
400
500
600
700
800
900
950
<div class="grid grid-cols-11 gap-1 text-center text-[10px]">
  <div class="rounded bg-sky-50 py-3 text-slate-700">50</div>
  <div class="rounded bg-sky-100 py-3 text-slate-700">100</div>
  <div class="rounded bg-sky-200 py-3 text-slate-700">200</div>
  <div class="rounded bg-sky-300 py-3 text-slate-800">300</div>
  <div class="rounded bg-sky-400 py-3 text-slate-900">400</div>
  <div class="rounded bg-sky-500 py-3 text-white">500</div>
  <div class="rounded bg-sky-600 py-3 text-white">600</div>
  <div class="rounded bg-sky-700 py-3 text-white">700</div>
  <div class="rounded bg-sky-800 py-3 text-white">800</div>
  <div class="rounded bg-sky-900 py-3 text-white">900</div>
  <div class="rounded bg-sky-950 py-3 text-white">950</div>
</div>

Ступень — это роль, а не просто «чуть темнее». Держите в голове такую таблицу ролей, и подбор цвета перестанет быть угадыванием:

СтупениРольПример
50–100Фон блока, подсветка строкиbg-amber-50
200–300Рамки, разделители, неактивные элементыborder-slate-200
400–500Иконки, декоративные акцентыtext-slate-400
600–700Заливка кнопок, активные состоянияbg-sky-600
800–950Текст, тёмные поверхностиtext-slate-900

Палитра — как набор красок с уже разведёнными оттенками. Художник не смешивает каждый раз заново: он берёт «третий слева» и знает, что в соседней картине тот же тон совпадёт. Ступени — это и есть готовые разведения.

Почему OKLCH

Цвета темы записаны как oklch(светлота хрома тон), а не в HEX. Практическая польза для вас:

  • Равномерность. Шаг между ступенями воспринимается глазом одинаково у всех оттенков — жёлтый не «выпадает» из ряда, как это было в HEX-палитрах.
  • Широкий охват. На современных экранах доступны цвета ярче, чем позволяет sRGB.
  • Предсказуемые вычисления. Осветлить или затемнить цвет можно, изменив одно число — светлоту.
/* так выглядит токен палитры */
--color-sky-600: oklch(58.8% 0.158 241.966);
/*                    │      │     └── тон (оттенок по кругу)
                       │      └──────── насыщенность
                       └─────────────── светлота */

Одно значение — много свойств

Цвет подставляется в любое свойство, где он уместен:

КлассСвойство
bg-sky-600background-color
text-sky-600color
border-sky-600border-color
ring-sky-600цвет «кольца» фокуса
divide-sky-200цвет разделителей между детьми
decoration-sky-400цвет подчёркивания
accent-sky-600цвет чекбоксов и радиокнопок
fill-sky-500 / stroke-sky-500SVG

Прозрачность через дробь

Любой цветовой класс принимает модификатор прозрачности:

/100
/60
/30
/10
<div class="flex flex-wrap gap-3">
  <div class="rounded-md bg-indigo-600 px-4 py-3 text-sm text-white">/100</div>
  <div class="rounded-md bg-indigo-600/60 px-4 py-3 text-sm text-white">/60</div>
  <div class="rounded-md bg-indigo-600/30 px-4 py-3 text-sm text-indigo-900">/30</div>
  <div class="rounded-md bg-indigo-600/10 px-4 py-3 text-sm text-indigo-900">/10</div>
</div>

Это удобнее, чем заводить отдельный светлый оттенок: прозрачный цвет «дружит» с любым фоном, в том числе в тёмной теме. Классический случай — подложка модального окна bg-slate-900/50.

Контраст: правило пары

Простое и почти всегда работающее правило: сумма ступеней фона и текста должна быть не меньше 900 при разнице не менее 500.

bg-100 + text-800 — читается
bg-600 + white — читается
bg-300 + text-500 — плохо
<div class="space-y-2">
  <div class="rounded-md bg-emerald-100 px-3 py-2 text-sm text-emerald-800">bg-100 + text-800 — читается</div>
  <div class="rounded-md bg-emerald-600 px-3 py-2 text-sm text-white">bg-600 + white — читается</div>
  <div class="rounded-md bg-emerald-300 px-3 py-2 text-sm text-emerald-500">bg-300 + text-500 — плохо</div>
</div>
Цвет не должен быть единственным носителем смысла: добавляйте текст или значок. «Красная строка» ничего не сообщит человеку с нарушением цветовосприятия и не прочитается скринридером.

Градиенты

Градиент собирается из направления и опорных точек:

<div class="space-y-3">
  <div class="h-16 rounded-lg bg-linear-to-r from-sky-500 to-indigo-500"></div>
  <div class="h-16 rounded-lg bg-linear-to-br from-amber-300 via-rose-400 to-fuchsia-600"></div>
</div>
<div class="bg-linear-to-r from-sky-500 to-indigo-500"></div>
<div class="bg-linear-to-br from-amber-300 via-rose-400 to-fuchsia-600"></div>
Имя изменилось: в Tailwind v3 класс назывался bg-gradient-to-r, в v4 — bg-linear-to-r (появились также bg-radial и bg-conic). Старое имя пока поддерживается, но в новом коде используйте новое.

Семантические цвета

В больших проектах на палитру надстраивают смысловой слой: не bg-slate-900, а bg-primary; не text-slate-500, а text-muted-foreground. Тогда смена темы — это смена нескольких переменных, а не правка сотни классов. Именно так устроен shadcn/ui — подробно в уроках 13 и 19.

bg-primary bg-secondary bg-muted
<div class="flex flex-wrap gap-3">
  <span class="rounded-md bg-primary px-3 py-2 text-sm text-primary-foreground">bg-primary</span>
  <span class="rounded-md bg-secondary px-3 py-2 text-sm text-secondary-foreground">bg-secondary</span>
  <span class="rounded-md bg-muted px-3 py-2 text-sm text-muted-foreground">bg-muted</span>
</div>