Изменение CSS средствами JavaScript: от classList до CSSOM

Раздел: Frontend -> CSS и JavaScript

Изменение CSS через JavaScript: основные подходы

Динамическое управление стилями - одна из ключевых задач фронтенд-разработки. JavaScript предоставляет несколько способов влиять на CSS, каждый со своими целями и ограничениями. Ниже разобраны варианты от самого эффективного до специализированных, с примерами кода и типичными ошибками.

Как изменить стиль элемента, не смешивая логику и представление?

Самый эффективный подход - работа с классами через classList. Он сохраняет разделение HTML, CSS и JavaScript: стили остаются в CSS-файлах, а JS только переключает классы. Это улучшает поддерживаемость и производительность (изменение класса вызывает пересчёт стилей, но не перезаписывает inline-правила).


// HTML: <div id="box" class="box"></div>
// CSS: .box { background: blue; width: 100px; height: 100px; }
//       .box.active { background: green; }

const box = document.getElementById('box');
box.classList.add('active');        // добавить класс
box.classList.remove('active');     // удалить
box.classList.toggle('active');     // переключить
  

Js работа с css (изменение css через javascript)

Пояснение шагов: сначала получаем элемент, затем вызываем методы add, remove или toggle. Метод toggle возвращает true если класс добавлен, иначе false - это удобно для проверки состояния.

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

  • Забыть точку при указании класса в CSS-файле (selector начинается с точки).
  • Попытка добавить класс с пробелом - classList.add('class1 class2') не сработает, нужно добавлять по одному или через classList.add('class1', 'class2').
  • Изменение уже существующего inline-стиля (например, style.background) может перекрыть класс из-за специфичности inline.

Решение: избегать одновременного использования inline-стилей и классов для одного и того же свойства. Если нужно временно изменить стиль, лучше использовать классы.

Как быстро изменить одно CSS-свойство напрямую?

Когда требуется изменить конкретное свойство у элемента без создания отдельного CSS-класса, используется свойство style объекта элемента. Это inline-стиль, имеющий наивысший приоритет после !important.


const element = document.querySelector('.my-element');
element.style.color = 'red';
element.style.backgroundColor = '#f0f0f0';
element.style.fontSize = '16px';
  

Пояснение: имена CSS-свойств преобразуются в camelCase (например, background-colorbackgroundColor). Значения задаются строками, включая единицы измерения.

Ошибки: забыть единицы (style.width = 100 - не сработает, нужно '100px'); опечатки в названиях свойств; попытка задать несуществующее свойство (ошибки не будет, но стиль не применится); конфликт с ранее установленными inline-стилями - перезапись происходит только тех свойств, которые явно указаны.

Решение: перед записью очищать предыдущие значения через element.style.cssText = '' или сбрасывать нужное свойство в пустую строку (element.style.color = '').

Как перезаписать все стили элемента одной строкой?

Свойство style.cssText позволяет задать целый блок inline-стилей. Это быстрее, чем устанавливать каждое свойство по отдельности, но полностью заменяет предыдущий inline-стиль.


const div = document.querySelector('div');
div.style.cssText = 'color: white; background: black; padding: 10px;';
// предшествующие inline-стили элемента будут удалены
  

Когда использовать: когда нужно сбросить все inline-стили и задать новый набор, например, при динамической смене темы на одной странице.

Проблема: cssText не очищает классовые стили, только inline. Также если требуется добавить стиль к существующим, проще использовать style.property или setProperty.

Как динамически менять темы оформления с помощью CSS-переменных?

Кастомные CSS-свойства (custom properties) позволяют определять переменные в CSS и изменять их через JavaScript. Это идеально для создания темной/светлой темы: меняется значение переменной, и все элементы, использующие её, обновляются автоматически.


/* CSS */
:root {
  --bg-color: #ffffff;
  --text-color: #000000;
}
body {
  background: var(--bg-color);
  color: var(--text-color);
}

// JavaScript
const root = document.documentElement;
root.style.setProperty('--bg-color', '#1a1a1a');
root.style.setProperty('--text-color', '#f0f0f0');
  

Пояснение: метод style.setProperty(propertyName, value, priority) принимает имя CSS-свойства, значение и необязательный приоритет ('important'). Имя переменной указывается с двойным дефисом ('--bg-color').

Ошибки: забыть двойной дефис в начале имени; неверный синтаксис значения (например, '10px' вместо '10px' - вроде верно, но если нужно число без единицы, то в CSS переменная будет воспринята как пользовательское значение, но не будет работать в calc()); попытка изменить переменную у элемента, который наследует значение от :root, - достаточно изменить у root.

Как программно добавить новое CSS-правило на страницу?

Если нужно динамически создать целый стиль (например, на основе пользовательских настроек), используют интерфейс CSSStyleSheet (CSSOM). Можно либо добавить правило в существующую таблицу стилей, либо создать новый элемент <style>.


// Вариант 1: через элемент <style>
const style = document.createElement('style');
style.textContent = `
  .dynamic-class {
    background: orange;
    border-radius: 8px;
  }
`;
document.head.appendChild(style);

// Вариант 2: через CSSStyleSheet.insertRule()
const sheet = document.styleSheets[0]; // первая таблица стилей (обычно основная)
sheet.insertRule('.dynamic-class { background: orange; }', sheet.cssRules.length);
  

Когда использовать: для создания динамических тем, загрузки стилей с сервера, адаптивных компонентов. Вариант с <style> проще, но создаёт отдельный узел. insertRule добавляет правило в существующую таблицу - это эффективнее, если таблиц немного.

Ошибки: попытка вставить правило до загрузки CSS файлов (stylesheet может быть пустым или из другого origin с ограничениями CORS); неправильный синтаксис селектора или правила; неучёт нумерации индексов (sheet.cssRules.length даёт количество существующих правил).

Решение: проверять наличие sheet.cssRules (некоторые браузеры не разрешают доступ к правилам из-за CORS) и использовать try-catch.

Расширенные примеры использования JavaScript для управления CSS

Пример 1. Анимация через requestAnimationFrame с инлайн-стилями (transform)

Создание плавного движения элемента без CSS-анимации. Изменяем свойство transform в каждом кадре.

Пример

const box = document.getElementById('animated-box');
let position = 0;
let direction = 1;

function animate() {
  position += direction;
  if (position > 300 || position < 0) direction *= -1;
  box.style.transform = `translateX(${position}px)`;
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);
  
Результат: элемент плавно перемещается вправо-влево, синхронизируясь с частотой обновления экрана.
  

Пример 2. Динамическое создание графика ширины с CSS-переменными

Изменение ширины столбцов диаграммы через JS-установку кастомного свойства.

Пример

/* CSS */
.bar {
  width: var(--width);
  height: 20px;
  background: steelblue;
  transition: width 0.3s;
}

// JavaScript
const bars = document.querySelectorAll('.bar');
const data = [40, 75, 120, 200];
bars.forEach((bar, i) => {
  bar.style.setProperty('--width', data[i] + 'px');
});
  
Результат: каждый столбец получает свою ширину, заданную через переменную. Значения можно менять в реальном времени, вызывая повторный setProperty.
  

Пример 3. Добавление стиля для псевдоэлемента через CSSOM

Стандартная работа с псевдоэлементами через JS невозможна, но можно вставить новое правило в существующую таблицу стилей, которое будет применяться к псевдоэлементу.

Пример

const sheet = document.styleSheets[0];
const rule = `.my-element::after {
  content: "⚡";
  font-size: 2em;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}`;
try {
  sheet.insertRule(rule, sheet.cssRules.length);
} catch (e) {
  console.error('Невозможно добавить правило:', e);
}
  
Результат: на странице появляется псевдоэлемент ::after с заданным содержимым. Изменение правила можно выполнять многократно - ранее добавленное правило переопределить удалением (sheet.deleteRule(index)).
  

Пример 4. Динамическая смена медиа-запроса через JavaScript

Изменение стиля в зависимости от ширины окна или ориентации устройства, но не через CSS, а через программное добавление правила в медиа-блок таблицы стилей.

Пример

const sheet = document.styleSheets[0];
const mediaQuery = '(max-width: 600px)';
const newRule = 'body { font-size: 14px; }';

// Создаём или получаем существующую медиа-группу
const mediaIndex = Array.from(sheet.cssRules).findIndex(
  rule => rule.media && rule.media.mediaText === mediaQuery
);

if (mediaIndex !== -1) {
  // Добавляем правило внутрь существующей медиа-группы
  sheet.cssRules[mediaIndex].insertRule(newRule, sheet.cssRules[mediaIndex].cssRules.length);
} else {
  // Создаём новую медиа-группу
  const idx = sheet.insertRule(`@media ${mediaQuery} { ${newRule} }`, sheet.cssRules.length);
}
  
Результат: при ширине окна менее 600px размер шрифта увеличивается. Правило существует только в рамках данной таблицы стилей - при её удалении или перезагрузке страницы стили возвращаются к исходным.
  

Пример 5. Использование getComputedStyle для чтения финальных стилей

Иногда нужно узнать итоговый стиль элемента (учитывая каскад), например, для анимации или расчётов. getComputedStyle возвращает объект стилей с реальными значениями.

Пример

const div = document.querySelector('.styled-div');
const computed = getComputedStyle(div);
const bgColor = computed.backgroundColor; // 'rgb(255, 0, 0)'
const fontSize = computed.fontSize;       // '20px' (в пикселях)
console.log(`Фон: ${bgColor}, шрифт: ${fontSize}`);
  
Результат: в консоли выводятся реальные значения, даже если в CSS было задано 'red' или '1.2em'. Это полезно для проверки после применения классов.
  

Пример 6. Удаление всех инлайн-стилей через style.cssText

Полный сброс инлайн-стилей элемента: присвоение пустой строки удаляет все inline-свойства.

Пример

const element = document.getElementById('reset-me');
element.style.cssText = '';
// эквивалентно: удалить весь атрибут style
  
После выполнения элемент выглядит так, как будто style вообще не был задан. Классовые стили остаются.
  

Изменение CSS через JavaScript - comments

En
Js работа с css (javascript)