CSS переменные vs SCSS переменные - когда какие?Сегодня покажу вам, как я выбираю между
CSS custom properties (
--var) и
SCSS-переменными (
$var). Оба инструмента решают похожую задачу, но работают в разное время и по-разному влияют на проект.
1) Как они живут
-
SCSS $var - подставляются
на этапе сборки. В итоговом CSS переменных уже нет. Быстро, просто, но
не изменить в рантайме.
-
CSS --var - существуют
в браузере, участвуют в
каскаде, могут меняться
через медиа- и контейнер-запросы, селекторы, JS. Идеальны для тем, адаптивов и динамики.
2) Примеры на пальцах
Тема/бренд + тёмный режим (CSS)
:root { --primary: #4f46e5; }
.button { background: var(--primary); }
/* Тёмная тема меняет только значение */
.dark { --primary: #7c3aed; }
Адаптив без дублирования (CSS)
:root { --gap: 8px; }
@media (min-width: 768px) {
:root { --gap: 16px; }
}
.grid { gap: var(--gap); }
Живая смена из JS (CSS)
document.documentElement.style.setProperty('--primary', '#22c55e');
Дизайн-токены, генерация классов (SCSS)
$colors: (
primary: #4f46e5,
success: #16a34a,
danger: #dc2626
);
@function color($name) { @return map-get($colors, $name); }
@each $name, $val in $colors {
.text-#{$name} { color: $val; }
}
.btn--primary { background: color(primary); }
Флюидная типографика (CSS)
:root { --fs-h1: clamp(1.75rem, 1rem + 3vw, 3rem); }
h1 { font-size: var(--fs-h1); }
3) Когда что выбрать
-
Берите SCSS $var, если:
- значения никогда не меняются в браузере;
- нужно удобно
генерировать кучу классов/правил из карт и циклов;
- вы хотите ранний фейл при ошибке (компилятор сразу ругнётся).
-
Берите CSS --var, если:
- требуется
темизация, переключатели, A/B, кастомизация у пользователя;
- значения зависят от
медиа/контейнер-запросов;
- хотите использовать
calc(),
clamp() и
каскад как фичу.
4) Частые ошибки
- «Почему
$primary не меняется в тёмной теме?» - потому что это SCSS и оно уже подставлено при сборке.
-
var(--x) без фоллбэка:
color: var(--link, #2563eb); /* ← безопаснее */
- Переопределение не там, где действует селектор. Помните:
CSS-переменные каскадируют — задавайте их на нужной “высоте” (
:root,
.dark, контейнер).
5) Любимый гибрид-подход (очень практично)
- Храню
источник правды в SCSS-карте → генерю из неё
CSS-переменные в
:root. Так у меня есть и удобство сборки, и сила рантайма.
$tokens: (
primary: #4f46e5,
spacing: 8px,
radius: 12px
);
:root {
@each $k, $v in $tokens {
--#{$k}: #{$v};
}
}
/* дальше в CSS / компоненте */
.card {
padding: var(--spacing);
border-radius: var(--radius);
background: var(--primary);
}
.dark { --primary: #7c3aed; }
6) Мини-практика (сделайте прямо сейчас)
1. Возьмите ваш
$colors в SCSS и сгенерируйте из него
:root { --color-name: value }.
2. Переключите тему добавлением класса
.dark на
<html> и переопределите 2–3 ключевых токена.
3. Переведите один медиазависимый размер (например, `gap`) на CSS-переменную как в примере выше.
7) Чеклист напоследок
- Нужна динамика/тема/адаптив →
CSS --var.
- Нужна генерация/сборка/статичность →
SCSS $var.
- Большой проект? Делайте
гибрид: токены →
:root через SCSS.
👉
@frontend_sovet