CSS переменные (custom properties) позволяют хранить значения один раз и использовать везде. Изменил одну переменную — обновилась вся тема. Плюс их можно читать и изменять через JavaScript.

- Синтаксис — объявление и использование
- Запасное значение — второй аргумент var()
- Область видимости — локальные переменные
- Тёмная тема через CSS переменные
- Управление переменными через JavaScript
- Переменные для каскадных анимаций
- Полная дизайн-система через CSS переменные
- Часто задаваемые вопросы о CSS переменных
- CSS переменные vs SASS переменные — в чём разница?
- Можно ли использовать переменные в media queries?
- Браузерная поддержка CSS custom properties?
Синтаксис — объявление и использование
Переменные объявляются с двойного тире --. Используются через функцию var(). Самое распространённое место объявления — :root (глобально).
/* Объявление в :root — доступны везде */
:root {
--color-primary: #2563eb;
--color-secondary: #7c3aed;
--color-success: #16a34a;
--color-danger: #dc2626;
--bg-page: #f9fafb;
--bg-card: #ffffff;
--text-main: #111827;
--text-muted: #6b7280;
--font-size-base: 16px;
--font-weight-bold: 700;
--border-radius-sm: 6px;
--border-radius-md: 12px;
--border-radius-full: 9999px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 32px;
--spacing-xl: 64px;
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.1);
}
/* Использование через var() */
.button {
background: var(--color-primary);
border-radius: var(--border-radius-sm);
padding: var(--spacing-sm) var(--spacing-md);
font-weight: var(--font-weight-bold);
}
.card {
background: var(--bg-card);
border-radius: var(--border-radius-md);
padding: var(--spacing-md);
box-shadow: var(--shadow-md);
}

Запасное значение — второй аргумент var()
/* Если переменная не определена — используется запасное значение */
.text {
color: var(--color-text, #333);
/* Если --color-text не задана → #333 */
}
/* Вложенные запасные значения */
.element {
background: var(--bg-custom, var(--bg-card, white));
/* Пробует --bg-custom, потом --bg-card, потом white */
}
/* Проверка наличия переменной */
.fallback {
font-size: var(--fs-custom, 1rem);
}

Область видимости — локальные переменные
Переменные подчиняются каскаду CSS — дочерние элементы наследуют переменные родителей. Можно переопределять переменные для конкретного компонента.
/* :root — глобальные */
:root { --accent: #2563eb; }
/* Переопределение в компоненте */
.card-green {
--accent: #16a34a; /* только для этой карточки */
}
.card-red {
--accent: #dc2626;
}
/* Оба используют одинаковый CSS, но разные цвета */
.card .badge {
background: var(--accent); /* будет синим, зелёным или красным */
}
/* Локальные переменные компонента */
.button {
--btn-color: var(--color-primary);
--btn-padding: 10px 24px;
--btn-radius: 8px;
background: var(--btn-color);
padding: var(--btn-padding);
border-radius: var(--btn-radius);
}
.button.large {
--btn-padding: 14px 32px; /* только изменяем то что нужно */
}
.button.danger {
--btn-color: var(--color-danger);
}

Тёмная тема через CSS переменные
Самый элегантный способ реализовать светлую и тёмную тему — переопределить переменные. Все компоненты автоматически переключаются.
/* Светлая тема (по умолчанию) */
:root {
--bg: #ffffff;
--bg-surface: #f9fafb;
--bg-hover: #f3f4f6;
--text: #111827;
--text-muted: #6b7280;
--border: #e5e7eb;
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
/* Тёмная тема через атрибут */
[data-theme="dark"] {
--bg: #111827;
--bg-surface: #1f2937;
--bg-hover: #374151;
--text: #f9fafb;
--text-muted: #9ca3af;
--border: #374151;
--shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}
/* Тёмная тема через системные настройки */
@media (prefers-color-scheme: dark) {
:root {
--bg: #111827;
--bg-surface: #1f2937;
--text: #f9fafb;
--text-muted: #9ca3af;
--border: #374151;
}
}
/* Все компоненты используют переменные — переключаются автоматически */
body {
background-color: var(--bg);
color: var(--text);
}
.card {
background: var(--bg-surface);
border: 1px solid var(--border);
box-shadow: var(--shadow);
}
.btn-ghost:hover {
background: var(--bg-hover);
}

Управление переменными через JavaScript
const root = document.documentElement;
// Получить значение переменной
const primary = getComputedStyle(root).getPropertyValue('--color-primary').trim();
console.log(primary); // "#2563eb"
// Изменить значение переменной
root.style.setProperty('--color-primary', '#dc2626');
// Теперь всё, что использует var(--color-primary), станет красным
// Переключение тёмной темы
const toggleTheme = () => {
const isDark = document.documentElement.dataset.theme === 'dark';
document.documentElement.dataset.theme = isDark ? 'light' : 'dark';
localStorage.setItem('theme', isDark ? 'light' : 'dark');
};
// Восстановить тему при загрузке
const savedTheme = localStorage.getItem('theme') || 'light';
document.documentElement.dataset.theme = savedTheme;
// Динамический акцентный цвет (например, выбор пользователя)
const colorPicker = document.getElementById('accent-color');
colorPicker.addEventListener('input', (e) => {
root.style.setProperty('--color-primary', e.target.value);
});

Переменные для каскадных анимаций
/* Задержка анимации через переменную */
.card {
opacity: 0;
animation: fadeIn 0.4s ease var(--delay, 0s) forwards;
}
/* Задаём разные задержки на каждой карточке */
.card:nth-child(1) { --delay: 0.0s; }
.card:nth-child(2) { --delay: 0.1s; }
.card:nth-child(3) { --delay: 0.2s; }
.card:nth-child(4) { --delay: 0.3s; }
.card:nth-child(5) { --delay: 0.4s; }
/* Или через inline style в HTML: */
/* <div class="card" style="--delay: 0.1s"> */

Полная дизайн-система через CSS переменные
:root {
/* === ЦВЕТА === */
/* Primary */
--clr-primary-50: #eff6ff;
--clr-primary-100: #dbeafe;
--clr-primary-500: #3b82f6;
--clr-primary-600: #2563eb;
--clr-primary-900: #1e3a8a;
/* Нейтральные */
--clr-gray-50: #f9fafb;
--clr-gray-100: #f3f4f6;
--clr-gray-500: #6b7280;
--clr-gray-900: #111827;
/* Статус */
--clr-success: #16a34a;
--clr-warning: #d97706;
--clr-danger: #dc2626;
/* === ТИПОГРАФИКА === */
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
--font-mono: 'Fira Code', 'Courier New', monospace;
--text-xs: 0.75rem; /* 12px */
--text-sm: 0.875rem; /* 14px */
--text-base: 1rem; /* 16px */
--text-lg: 1.125rem; /* 18px */
--text-xl: 1.25rem; /* 20px */
--text-2xl: 1.5rem; /* 24px */
--text-3xl: 1.875rem; /* 30px */
--text-4xl: 2.25rem; /* 36px */
/* === ОТСТУПЫ (кратно 4) === */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-6: 24px;
--space-8: 32px;
--space-12: 48px;
--space-16: 64px;
/* === СКРУГЛЕНИЯ === */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--radius-full: 9999px;
/* === ТЕНИ === */
--shadow-xs: 0 1px 2px rgba(0,0,0,0.05);
--shadow-sm: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);
--shadow-md: 0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.06);
--shadow-lg: 0 10px 15px rgba(0,0,0,0.1), 0 4px 6px rgba(0,0,0,0.05);
/* === АНИМАЦИИ === */
--duration-fast: 150ms;
--duration-normal: 250ms;
--duration-slow: 400ms;
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
}

Часто задаваемые вопросы о CSS переменных
CSS переменные vs SASS переменные — в чём разница?
SASS переменные ($color: blue) — статические, вычисляются при компиляции, в браузер попадает уже готовый CSS без переменных. CSS custom properties (--color: blue) — живут в браузере, доступны через JavaScript, наследуются и могут меняться динамически. Главное преимущество CSS переменных: можно переключать темы без перезагрузки страницы, переопределять для отдельных компонентов и читать из JavaScript. SASS переменные — только для статических значений в момент сборки.
Можно ли использовать переменные в media queries?
В условиях медиазапроса — нет: @media (max-width: var(--breakpoint)) не работает. Но внутри медиазапроса переменные работают нормально, и можно переопределять переменные в медиазапросе:
:root { --columns: 3; --gutter: 24px; }
@media (max-width: 768px) {
:root { --columns: 1; --gutter: 16px; }
}
.grid {
grid-template-columns: repeat(var(--columns), 1fr);
gap: var(--gutter);
}
Браузерная поддержка CSS custom properties?
CSS переменные поддерживаются всеми современными браузерами (Chrome 49+, Firefox 31+, Safari 9.1+, Edge 15+). Общая поддержка — 97%+ глобально. Единственное исключение — Internet Explorer 11, который не поддерживает CSS custom properties вообще. Если нужна поддержка IE11, используй препроцессоры (SASS/Less) или PostCSS плагины.



