Стили и классы в JavaScript
Управление внешним видом элементов через JavaScript: className и classList (add, remove, toggle, contains, replace), свойство style и cssText, чтение итоговых значений с помощью getComputedStyle.
Введение
Существует два способа изменить внешний вид элемента средствами JavaScript:
- Добавить или убрать CSS-класс — стили хранятся в таблице стилей, а JavaScript лишь включает или выключает класс. Это предпочтительный подход.
- Задать встроенный стиль напрямую на элементе через свойство
style— удобно, когда значение вычисляется во время выполнения (например, позиция, зависящая от положения мыши).
В этой главе рассматриваются оба подхода: API className и classList для работы с классами, свойство style и cssText для встроенных стилей, а также getComputedStyle для чтения итоговых стилей, которые браузер действительно применил. Для более широкого обзора CSS и DOM см. Работа со стилями в DOM.
Свойство style
Прямое управление стилями
Свойство style — это object, ключами которого являются встроенные CSS-свойства элемента. Чтобы изменить стиль элемента напрямую через JavaScript, нужно присвоить значение одному из этих ключей. Вот пример изменения цвета фона и размера шрифта параграфа:
<!-- snippet: html-result -->
<style>
#myParagraph {
color: white; /* Ensures text is readable on a blue background */
}
</style>
<div id="myParagraph">This is a paragraph.</div>
<script>
document.getElementById("myParagraph").style.backgroundColor = "blue";
document.getElementById("myParagraph").style.fontSize = "16px";
</script>Обратите внимание на имена свойств: CSS использует дефисы (background-color, font-size), а object style — camelCase (backgroundColor, fontSize). Многословные свойства всегда следуют этому правилу, а у свойств с префиксом ведущий дефис превращается в заглавную букву (-moz-border-radius становится MozBorderRadius). Значения всегда являются string, и числовые CSS-значения должны включать единицу измерения — el.style.fontSize = "16px", а не 16.
Присваивание el.style.backgroundColor записывает значение в атрибут style="..." элемента, поэтому оно затрагивает только этот элемент и переопределяет правила таблицы стилей (имеет такой же вес, как авторский встроенный стиль). Чтобы удалить встроенное значение, присвойте пустую string: el.style.fontSize = "".
Этот метод предоставляет прямой контроль, но может быть громоздким при множественных изменениях стилей.
Использование style.cssText
Для эффективного применения нескольких изменений стилей используйте style.cssText:
<!-- snippet: html-result -->
<style>
#myParagraph {
padding: 5px;
width: 200px;
text-align: center;
}
</style>
<div id="myParagraph">Another paragraph.</div>
<script>
document.getElementById("myParagraph").style.cssText = "background-color: blue; font-size: 16px; border: 1px solid black";
</script>Этот подход объединяет изменения стилей в одну операцию. Учтите, что cssText заменяет весь встроенный стиль, удаляя все ранее заданные свойства элемента. Используйте его, когда хотите начать с чистого листа; используйте отдельные присваивания style.*, когда нужно изменить одно свойство, не затрагивая остальные.
Чтение стилей с помощью getComputedStyle
Свойство style отражает только встроенные стили — значения, заданные в атрибуте style или через JavaScript. Для всего, что приходит из таблицы стилей, оно возвращает пустую string. Чтобы прочитать итоговое, вычисленное значение, которое браузер действительно отобразил (из всех таблиц стилей, встроенных правил и унаследованных значений), используйте getComputedStyle:
<!-- snippet: html-result -->
<style>
#box { width: 10em; padding: 5px; }
</style>
<div id="box">Measure me</div>
<script>
const box = document.getElementById("box");
const styles = getComputedStyle(box);
// Computed values are resolved to absolute units (px), not the "10em" we wrote:
console.log(styles.width); // "160px" (10em at the default 16px font size)
console.log(styles.padding); // "5px"
</script>Несколько правил, которые следует помнить:
- Возвращаемый object доступен только для чтения — присваивание к нему не имеет эффекта; используйте
element.styleдля изменения стилей. - Значения вычислены: длины возвращаются в пикселях, цвета — в формате
rgb(...). - Всегда читайте конкретное свойство (
getComputedStyle(el).marginTop) и предпочитайте полное имя — некоторые сокращённые свойства (margin,padding) возвращаются непоследовательно в разных браузерах.
className и classList
Существует два способа читать и записывать классы элемента:
element.className— это одна string, содержащая весь атрибутclass. Присваивание к нему заменяет все классы сразу:el.className = "active warning". Удобно для полной замены всех классов, но неудобно для изменения только одного.element.classList— это специальный object с методами для работы с отдельными классами:add,remove,toggle,containsиreplace. Именно к нему вы будете обращаться чаще всего, так как он позволяет изменить один класс, не затрагивая остальные.
Методы:
| Метод | Что делает |
|---|---|
classList.add("a", "b") | Добавляет один или несколько классов (ничего не делает, если уже присутствуют) |
classList.remove("a", "b") | Удаляет один или несколько классов (ничего не делает, если отсутствуют) |
classList.toggle("a") | Добавляет класс, если он отсутствует, и удаляет, если присутствует |
classList.contains("a") | Возвращает true/false — есть ли у элемента этот класс? |
classList.replace("old", "new") | Заменяет одно имя класса другим |
(Свойство называется className, а не class, потому что class — зарезервированное слово в JavaScript — см. Атрибуты и свойства.)
Добавление и удаление классов
Использование API classList упрощает манипуляции с классами.
Добавление класса
<!-- snippet: html-result -->
<style>
.new-class {
font-weight: bold;
color: green;
}
</style>
<div id="myDiv">Class manipulation</div>
<script>
document.getElementById("myDiv").classList.add("new-class");
</script>Удаление класса
<!-- snippet: html-result -->
<style>
.existing-class {
text-decoration: underline;
color: red;
}
</style>
<div id="myDiv" class="existing-class">Another manipulation example</div>
<script>
document.getElementById("myDiv").classList.remove("existing-class");
</script>Переключение класса
Функциональность toggle эффективна для переключения стилей, например тем оформления:
<!-- snippet: html-result -->
<style>
.dark-mode {
background-color: black;
color: white;
}
</style>
<button id="toggleButton">Toggle Dark Mode</button>
<script>
document.getElementById("toggleButton").addEventListener("click", function() {
document.body.classList.toggle("dark-mode");
});
</script>Работа с несколькими классами
Управление несколькими классами одновременно:
<!-- snippet: html-result -->
<style>
.first-class { background-color: yellow; }
.second-class { border: 2px dashed blue; }
.third-class { display: none; }
.fourth-class { font-size: 14px; }
</style>
<div id="myDiv">Multiple class handling</div>
<script>
document.getElementById("myDiv").classList.add("first-class", "second-class");
document.getElementById("myDiv").classList.remove("third-class", "fourth-class");
</script>Проверка и замена классов
Используйте contains, чтобы проверить наличие класса, и replace, чтобы заменить один класс другим за один вызов:
const el = document.getElementById("myDiv");
el.classList.contains("active"); // false
el.classList.add("active");
el.classList.contains("active"); // true
// Swap "active" for "disabled" (returns true if the swap happened):
el.classList.replace("active", "disabled"); // true
el.classList.contains("active"); // false
el.classList.contains("disabled"); // truetoggle также принимает необязательный второй аргумент, который принудительно задаёт результат: classList.toggle("open", isOpen) добавляет класс, когда isOpen равно true, и удаляет, когда false — что удобно, когда нужное состояние уже хранится в boolean.
Лучшие практики: классы или встроенные стили
Предпочитайте классы встроенным стилям. Храните стили в CSS, а JavaScript пусть только переключает имена классов. Это разделяет представление и поведение, позволяя дизайнерам менять внешний вид, не трогая скрипты; один и тот же класс можно повторно использовать во многих элементах, а стили остаются в одном месте, где их легко найти.
Обращайтесь к element.style только тогда, когда значение действительно должно вычисляться во время выполнения — позиция элемента, следящего за мышью, ширина, производная от данных, цвет, выбранный пользователем. Такие значения не могут находиться в статической таблице стилей, поэтому встроенный стиль здесь — правильный инструмент.
Когда смена класса должна анимироваться, а не происходить мгновенно, задайте CSS transition для нужного свойства и позвольте переключению класса управлять анимацией. Браузер обработает её по собственному оптимизированному пути, что плавнее, чем пошаговое изменение значений из JavaScript. Подробнее см. CSS-анимации.
Заключение
Используйте classList (add, remove, toggle, contains, replace) для управления классами и доверяйте таблице стилей визуальную работу; обращайтесь к element.style только для значений, которые должны вычисляться во время выполнения; читайте итоговые, применённые значения с помощью getComputedStyle — помня, что он доступен только для чтения. Хранение стилей в CSS и переключение классов через JavaScript делает код более удобным в сопровождении и быстрее отрисовывается.