← HTML & CSS/CSS-переменные (Custom Properties)#28 из 383← ПредыдущийСледующий →+15 XP
Полезно по теме:Гайд: старт в frontendПрактика: DOM и событияТермин: DOMМаршрут: старт с нуля

CSS-переменные (Custom Properties)

Представь: дизайнер меняет фирменный цвет с синего на фиолетовый. Без переменных тебе нужно найти и заменить #3b82f6 в 50 местах файла. С CSS-переменными — поменять одну строку в начале файла. Это и есть Custom Properties — нативные переменные CSS, встроенные прямо в браузер.

Синтаксис

/* Объявление: двойной дефис + имя */
:root {
  --color-primary: #7b2ff7;
  --color-text: #1a202c;
  --spacing-md: 16px;
  --border-radius: 8px;
}

/* Использование: var() */
.btn {
  background-color: var(--color-primary);
  padding: var(--spacing-md);
  border-radius: var(--border-radius);
}

:root — глобальная область видимости

:root — это <html>, самый верхний элемент. Переменные, объявленные здесь, доступны во всём документе.

:root {
  --color-primary: #7b2ff7;
  --color-secondary: #3b82f6;
  --color-success: #38a169;
  --color-danger: #e53e3e;
  --font-size-base: 16px;
  --font-size-sm: 14px;
  --font-size-lg: 20px;
}

Локальная область видимости

Переменная доступна только внутри элемента, где объявлена, и его потомкам.

.card {
  --card-padding: 24px;
  --card-bg: white;
  padding: var(--card-padding);
  background: var(--card-bg);
}

.card .card-header {
  padding: var(--card-padding);  /* Работает — потомок .card */
}

.other-element {
  padding: var(--card-padding);  /* Не работает — переменная не видна */
}

Запасное значение (fallback)

color: var(--color-brand, #7b2ff7);      /* Если --color-brand не задана, используй #7b2ff7 */
font-size: var(--size-title, var(--size-base, 16px));  /* Цепочка fallback */

Тёмная тема через переменные

Это киллер-фича CSS-переменных. Вместо дублирования всех стилей — просто меняем значения переменных:

:root {
  --bg: white;
  --text: #1a202c;
  --card-bg: #f7fafc;
}

[data-theme="dark"] {
  --bg: #1a202c;
  --text: #f7fafc;
  --card-bg: #2d3748;
}

body { background: var(--bg); color: var(--text); }
.card { background: var(--card-bg); }

Переключить тему: document.documentElement.setAttribute('data-theme', 'dark')

CSS-переменные vs SCSS-переменные

| | CSS Custom Properties | SCSS Variables |

|---|---|---|

| Работает в браузере | Да | Нет (компилируется) |

| Изменяемы в JS | Да | Нет |

| Реагируют на медиа-запросы | Да | Нет |

| Локальная область видимости | Да | Нет |

| Поддержка браузеров | Все современные | Везде |

CSS-переменные живут в браузере — их можно читать и менять через JavaScript.

Управление переменными через JavaScript

// Читать
const primary = getComputedStyle(document.documentElement)
  .getPropertyValue('--color-primary').trim()

// Задать на корневом элементе
document.documentElement.style.setProperty('--color-primary', '#e53e3e')

// Задать локально на элементе
element.style.setProperty('--card-padding', '32px')

Типичные ошибки

Ошибка 1: Пробел между -- и именем

-- color-primary: red;   /* Ошибка! */
--color-primary: red;    /* Правильно */

Ошибка 2: Забыть var()

color: --color-primary;         /* Неправильно — это не работает */
color: var(--color-primary);    /* Правильно */

Ошибка 3: Переменная не определена — нет ошибки, просто невалидное значение

color: var(--undefined-var);  /* Применится как 'initial' — без ошибки в консоли */
/* Используй fallback: */
color: var(--undefined-var, black);

В реальных проектах

Каждый серьёзный проект сегодня использует CSS-переменные для дизайн-токенов: цветов, отступов, теней, радиусов. Они заменяют SCSS-переменные там, где нужна динамика. Tailwind CSS в версии 4 полностью перешёл на Custom Properties. Материал-дизайн от Google и Ant Design хранят свои темы именно в CSS-переменных.

Примеры

CSS-переменные: создание и переключение тёмной темы

// Задаём переменные через JS на :root
const root = document.documentElement

// Светлая тема по умолчанию
root.style.setProperty('--bg-primary', '#ffffff')
root.style.setProperty('--bg-secondary', '#f7fafc')
root.style.setProperty('--text-primary', '#1a202c')
root.style.setProperty('--text-secondary', '#718096')
root.style.setProperty('--color-accent', '#7b2ff7')
root.style.setProperty('--border-color', '#e2e8f0')
root.style.setProperty('--border-radius', '8px')
root.style.setProperty('--spacing', '16px')

// Стили, которые используют переменные
const styleTag = document.createElement('style')
styleTag.textContent = `
  body {
    background: var(--bg-primary);
    color: var(--text-primary);
    font-family: Arial, sans-serif;
    padding: var(--spacing);
    transition: background 0.3s, color 0.3s;
  }
  .card {
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    padding: var(--spacing);
    margin-bottom: var(--spacing);
  }
  .card-title {
    color: var(--color-accent);
    font-weight: 700;
    margin: 0 0 8px;
  }
  .card-text {
    color: var(--text-secondary);
    margin: 0;
  }
  .theme-btn {
    background: var(--color-accent);
    color: white;
    border: none;
    padding: 8px 16px;
    border-radius: var(--border-radius);
    cursor: pointer;
  }
`
document.head.appendChild(styleTag)

// Создаём карточку
const card = document.createElement('div')
card.className = 'card'
card.innerHTML = '<h3 class="card-title">Урок CSS</h3><p class="card-text">CSS-переменные делают темы простыми</p>'
document.body.appendChild(card)

// Кнопка переключения темы
const themeBtn = document.createElement('button')
themeBtn.className = 'theme-btn'
themeBtn.textContent = 'Тёмная тема'
document.body.appendChild(themeBtn)

let isDark = false
themeBtn.addEventListener('click', () => {
  isDark = !isDark
  if (isDark) {
    root.style.setProperty('--bg-primary', '#1a202c')
    root.style.setProperty('--bg-secondary', '#2d3748')
    root.style.setProperty('--text-primary', '#f7fafc')
    root.style.setProperty('--text-secondary', '#a0aec0')
    root.style.setProperty('--border-color', '#4a5568')
    themeBtn.textContent = 'Светлая тема'
  } else {
    root.style.setProperty('--bg-primary', '#ffffff')
    root.style.setProperty('--bg-secondary', '#f7fafc')
    root.style.setProperty('--text-primary', '#1a202c')
    root.style.setProperty('--text-secondary', '#718096')
    root.style.setProperty('--border-color', '#e2e8f0')
    themeBtn.textContent = 'Тёмная тема'
  }
  console.log('Тема переключена:', isDark ? 'тёмная' : 'светлая')
})

// Читаем переменные
const styles = getComputedStyle(root)
console.log('--color-accent:', styles.getPropertyValue('--color-accent').trim())
console.log('--border-radius:', styles.getPropertyValue('--border-radius').trim())
console.log('--spacing:', styles.getPropertyValue('--spacing').trim())

// Локальная переменная на конкретном элементе
card.style.setProperty('--card-scale', '1.05')
console.log('Локальная --card-scale:', getComputedStyle(card).getPropertyValue('--card-scale').trim())

CSS-переменные (Custom Properties)

Представь: дизайнер меняет фирменный цвет с синего на фиолетовый. Без переменных тебе нужно найти и заменить #3b82f6 в 50 местах файла. С CSS-переменными — поменять одну строку в начале файла. Это и есть Custom Properties — нативные переменные CSS, встроенные прямо в браузер.

Синтаксис

/* Объявление: двойной дефис + имя */
:root {
  --color-primary: #7b2ff7;
  --color-text: #1a202c;
  --spacing-md: 16px;
  --border-radius: 8px;
}

/* Использование: var() */
.btn {
  background-color: var(--color-primary);
  padding: var(--spacing-md);
  border-radius: var(--border-radius);
}

:root — глобальная область видимости

:root — это <html>, самый верхний элемент. Переменные, объявленные здесь, доступны во всём документе.

:root {
  --color-primary: #7b2ff7;
  --color-secondary: #3b82f6;
  --color-success: #38a169;
  --color-danger: #e53e3e;
  --font-size-base: 16px;
  --font-size-sm: 14px;
  --font-size-lg: 20px;
}

Локальная область видимости

Переменная доступна только внутри элемента, где объявлена, и его потомкам.

.card {
  --card-padding: 24px;
  --card-bg: white;
  padding: var(--card-padding);
  background: var(--card-bg);
}

.card .card-header {
  padding: var(--card-padding);  /* Работает — потомок .card */
}

.other-element {
  padding: var(--card-padding);  /* Не работает — переменная не видна */
}

Запасное значение (fallback)

color: var(--color-brand, #7b2ff7);      /* Если --color-brand не задана, используй #7b2ff7 */
font-size: var(--size-title, var(--size-base, 16px));  /* Цепочка fallback */

Тёмная тема через переменные

Это киллер-фича CSS-переменных. Вместо дублирования всех стилей — просто меняем значения переменных:

:root {
  --bg: white;
  --text: #1a202c;
  --card-bg: #f7fafc;
}

[data-theme="dark"] {
  --bg: #1a202c;
  --text: #f7fafc;
  --card-bg: #2d3748;
}

body { background: var(--bg); color: var(--text); }
.card { background: var(--card-bg); }

Переключить тему: document.documentElement.setAttribute('data-theme', 'dark')

CSS-переменные vs SCSS-переменные

| | CSS Custom Properties | SCSS Variables |

|---|---|---|

| Работает в браузере | Да | Нет (компилируется) |

| Изменяемы в JS | Да | Нет |

| Реагируют на медиа-запросы | Да | Нет |

| Локальная область видимости | Да | Нет |

| Поддержка браузеров | Все современные | Везде |

CSS-переменные живут в браузере — их можно читать и менять через JavaScript.

Управление переменными через JavaScript

// Читать
const primary = getComputedStyle(document.documentElement)
  .getPropertyValue('--color-primary').trim()

// Задать на корневом элементе
document.documentElement.style.setProperty('--color-primary', '#e53e3e')

// Задать локально на элементе
element.style.setProperty('--card-padding', '32px')

Типичные ошибки

Ошибка 1: Пробел между -- и именем

-- color-primary: red;   /* Ошибка! */
--color-primary: red;    /* Правильно */

Ошибка 2: Забыть var()

color: --color-primary;         /* Неправильно — это не работает */
color: var(--color-primary);    /* Правильно */

Ошибка 3: Переменная не определена — нет ошибки, просто невалидное значение

color: var(--undefined-var);  /* Применится как 'initial' — без ошибки в консоли */
/* Используй fallback: */
color: var(--undefined-var, black);

В реальных проектах

Каждый серьёзный проект сегодня использует CSS-переменные для дизайн-токенов: цветов, отступов, теней, радиусов. Они заменяют SCSS-переменные там, где нужна динамика. Tailwind CSS в версии 4 полностью перешёл на Custom Properties. Материал-дизайн от Google и Ant Design хранят свои темы именно в CSS-переменных.

Примеры

CSS-переменные: создание и переключение тёмной темы

// Задаём переменные через JS на :root
const root = document.documentElement

// Светлая тема по умолчанию
root.style.setProperty('--bg-primary', '#ffffff')
root.style.setProperty('--bg-secondary', '#f7fafc')
root.style.setProperty('--text-primary', '#1a202c')
root.style.setProperty('--text-secondary', '#718096')
root.style.setProperty('--color-accent', '#7b2ff7')
root.style.setProperty('--border-color', '#e2e8f0')
root.style.setProperty('--border-radius', '8px')
root.style.setProperty('--spacing', '16px')

// Стили, которые используют переменные
const styleTag = document.createElement('style')
styleTag.textContent = `
  body {
    background: var(--bg-primary);
    color: var(--text-primary);
    font-family: Arial, sans-serif;
    padding: var(--spacing);
    transition: background 0.3s, color 0.3s;
  }
  .card {
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    padding: var(--spacing);
    margin-bottom: var(--spacing);
  }
  .card-title {
    color: var(--color-accent);
    font-weight: 700;
    margin: 0 0 8px;
  }
  .card-text {
    color: var(--text-secondary);
    margin: 0;
  }
  .theme-btn {
    background: var(--color-accent);
    color: white;
    border: none;
    padding: 8px 16px;
    border-radius: var(--border-radius);
    cursor: pointer;
  }
`
document.head.appendChild(styleTag)

// Создаём карточку
const card = document.createElement('div')
card.className = 'card'
card.innerHTML = '<h3 class="card-title">Урок CSS</h3><p class="card-text">CSS-переменные делают темы простыми</p>'
document.body.appendChild(card)

// Кнопка переключения темы
const themeBtn = document.createElement('button')
themeBtn.className = 'theme-btn'
themeBtn.textContent = 'Тёмная тема'
document.body.appendChild(themeBtn)

let isDark = false
themeBtn.addEventListener('click', () => {
  isDark = !isDark
  if (isDark) {
    root.style.setProperty('--bg-primary', '#1a202c')
    root.style.setProperty('--bg-secondary', '#2d3748')
    root.style.setProperty('--text-primary', '#f7fafc')
    root.style.setProperty('--text-secondary', '#a0aec0')
    root.style.setProperty('--border-color', '#4a5568')
    themeBtn.textContent = 'Светлая тема'
  } else {
    root.style.setProperty('--bg-primary', '#ffffff')
    root.style.setProperty('--bg-secondary', '#f7fafc')
    root.style.setProperty('--text-primary', '#1a202c')
    root.style.setProperty('--text-secondary', '#718096')
    root.style.setProperty('--border-color', '#e2e8f0')
    themeBtn.textContent = 'Тёмная тема'
  }
  console.log('Тема переключена:', isDark ? 'тёмная' : 'светлая')
})

// Читаем переменные
const styles = getComputedStyle(root)
console.log('--color-accent:', styles.getPropertyValue('--color-accent').trim())
console.log('--border-radius:', styles.getPropertyValue('--border-radius').trim())
console.log('--spacing:', styles.getPropertyValue('--spacing').trim())

// Локальная переменная на конкретном элементе
card.style.setProperty('--card-scale', '1.05')
console.log('Локальная --card-scale:', getComputedStyle(card).getPropertyValue('--card-scale').trim())

Задание

Создай CSS с тремя переменными в `:root`: `--primary` для цвета кнопки, `--padding` для отступов, `--radius` для скруглений. Используй эти переменные в стилях компонентов через `var()`. Добавь кнопку переключения темы: при клике меняй значение `--primary` на `#e53e3e`.

Подсказка

Объяви переменные в `:root` с двойным дефисом: `--primary: #7b2ff7`. Используй через `var(--primary)`. При клике `document.documentElement.style.setProperty('--primary', '#e53e3e')` меняет переменную для всего документа.

Загружаем среду выполнения...
Загружаем AI-помощника...