Работа со стилями в DOM
Как стилизовать элементы DOM в JavaScript: инлайн-стили, style и cssText, чтение значений через getComputedStyle и управление классами через classList API.
При работе с Document Object Model (DOM) в JavaScript изменение внешнего вида элемента во время выполнения программы является одной из самых распространённых задач. В этом руководстве рассматриваются практические способы применения стилей к элементам DOM: задание инлайн-стилей, чтение и установка отдельных CSS-свойств через свойство style, одновременная замена нескольких свойств с помощью cssText, чтение вычисленных стилей через getComputedStyle(), а также — рекомендуемый подход для большинства случаев — переключение CSS-классов через classList API.
Коротко: предпочитайте классы инлайн-стилям. Прямое управление стилями уместно для значений, вычисляемых во время выполнения (позиция, динамически выбираемый цвет), но для всего, что представляет состояние — «активно», «выполнено», «ошибка» — определите класс в CSS и переключайте его из JavaScript. В этом руководстве показаны оба подхода с объяснением того, когда каждый из них является правильным инструментом. Для более широкого обзора стилизации элементов см. Стили и классы.
Инлайн-стили
Инлайн-стили применяют CSS непосредственно к HTML-элементу через его атрибут style. Они удобны для быстрых единичных изменений, но плохо масштабируются: они смешивают представление с разметкой, не допускают повторного использования и выигрывают в каждом споре о специфичности, кроме !important, что делает их трудными для переопределения в будущем.
Пример
<div id="inlineStyleExample">This text will be styled using inline styles.</div>
<button onclick="applyInlineStyle()">Apply Inline Style</button>
<script>
function applyInlineStyle() {
const element = document.getElementById('inlineStyleExample');
element.style.color = 'red';
element.style.fontSize = '20px';
}
</script>В этом примере нажатие кнопки применит инлайн-стили к элементу div, изменив цвет текста на красный и размер шрифта на 20 пикселей.
Установка стилей через свойство style
Свойство style предоставляет объект CSSStyleDeclaration, который соответствует инлайн-стилю элемента. Чтение и запись через него — это JavaScript-эквивалент редактирования атрибута style, поэтому он имеет те же компромиссы, что и инлайн-стили, но позволяет вычислять значения динамически.
Два правила, которые часто сбивают с толку:
- Имена CSS-свойств записываются в camelCase. Свойства с дефисом, такие как
font-sizeиbackground-color, становятсяstyle.fontSizeиstyle.backgroundColor. Исключение составляетfloat, который записывается какstyle.cssFloat, посколькуfloatявляется зарезервированным словом. - Значения — это строки с единицами измерения.
element.style.width = 200ничего не делает; необходимо писатьelement.style.width = '200px'. Аналогично, чтениеelement.style.colorпосле его установки возвращает строку вида'rgb(0, 0, 255)'.
Пример
<div id="stylePropertyExample">This text will be styled using JavaScript.</div>
<button onclick="applyStyleProperty()">Apply Style Property</button>
<script>
function applyStyleProperty() {
const element = document.getElementById('stylePropertyExample');
element.style.color = 'blue';
element.style.fontSize = '18px';
element.style.margin = '10px';
}
</script>В этом примере нажатие кнопки применит несколько стилей к элементу div с помощью свойства style. Цвет текста установится синим, размер шрифта — 18 пикселей, а также добавится отступ в 10 пикселей.
Установка нескольких свойств одновременно с помощью cssText
Назначение одного свойства за раз вызывает отдельную запись каждый раз. Когда нужно установить сразу несколько свойств, style.cssText позволяет назначить их в одном выражении, используя обычный CSS-синтаксис:
element.style.cssText = 'color: white; background-color: navy; padding: 8px;';Имейте в виду, что назначение cssText заменяет все существующие инлайн-стили, поэтому используйте его для установки полного блока, а не для изменения одного значения. Чтобы удалить отдельное свойство, установите его равным пустой строке (element.style.color = '') или вызовите element.style.removeProperty('color').
Чтение фактического стиля через getComputedStyle()
Свойство style отражает только инлайн-стили. Если цвет задан через таблицу стилей или класс, element.style.color будет пустой строкой. Чтобы прочитать значение, которое браузер фактически применил — после обработки таблиц стилей, классов и наследования — используйте window.getComputedStyle():
<p id="styledByCss">I am styled by a stylesheet.</p>
<button onclick="readStyle()">Read computed color</button>
<script>
function readStyle() {
const element = document.getElementById('styledByCss');
// element.style.color would be '' — the color comes from CSS, not inline.
const computed = window.getComputedStyle(element);
alert('Computed color: ' + computed.color);
}
</script>
<style>
#styledByCss {
color: green;
}
</style>Вычисленные значения возвращаются в нормализованном, доступном только для чтения виде — цвета как rgb(...), длины в px — поэтому getComputedStyle(element).color возвращает 'rgb(0, 128, 0)', а не 'green'.
Управление классами
Управление классами — рекомендуемый способ стилизации элементов: стили находятся в CSS, а JavaScript только включает и выключает классы. Свойство classList предоставляет небольшой, хорошо именованный API — add(), remove(), toggle(), contains(), replace() и item() — который яснее и безопаснее, чем работа со строками через className.
Почему предпочесть classList вместо className? Запись element.className = 'highlight' перезаписывает все существующие классы, поэтому можно случайно удалить классы, на которые полагается другая часть кода. classList.add('highlight') добавляет только этот один класс, не затрагивая остальные.
Добавление классов
Метод add() добавляет один или несколько классов к элементу. Добавление уже существующего класса ничего не делает, поэтому его можно безопасно вызывать многократно.
Пример
<div id="addClassExample">This element will have classes added.</div>
<button onclick="addClass()">Add Class</button>
<script>
function addClass() {
const element = document.getElementById('addClassExample');
element.classList.add('highlight', 'text-large');
}
</script>
<style>
.highlight {
background-color: yellow;
}
.text-large {
font-size: 24px;
}
</style>В этом примере нажатие кнопки добавит классы highlight и text-large к элементу div, применив соответствующие стили.
Удаление классов
Метод remove() удаляет один или несколько классов из элемента. Удаление отсутствующего класса не приводит к ошибке, поэтому предварительная проверка не нужна.
Пример
<div id="removeClassExample" class="highlight text-large">
This element will have classes removed.
</div>
<button onclick="removeClass()">Remove Class</button>
<script>
function removeClass() {
const element = document.getElementById('removeClassExample');
element.classList.remove('highlight', 'text-large');
}
</script>
<style>
.highlight {
background-color: yellow;
}
.text-large {
font-size: 24px;
}
</style>Здесь нажатие кнопки удалит классы highlight и text-large из элемента div.
Переключение классов
Метод toggle() добавляет класс, если он отсутствует, и удаляет его, если он присутствует — идеально для состояний вкл/выкл, таких как открытое меню или выполненная задача. Он возвращает true, если класс присутствует после вызова, и false в противном случае.
Также можно принудительно задать результат с помощью второго аргумента типа boolean: toggle('active', true) всегда добавляет класс, а toggle('active', false) всегда удаляет его. Это удобно, когда желаемое состояние берётся из переменной: element.classList.toggle('active', isActive).
Пример
<div id="toggleClassExample">Click me to toggle the highlight class.</div>
<button onclick="toggleClass()">Toggle Class</button>
<script>
function toggleClass() {
const element = document.getElementById('toggleClassExample');
element.classList.toggle('highlight');
}
</script>
<style>
.highlight {
background-color: yellow;
}
.text-large {
font-size: 24px;
}
</style>В этом примере нажатие кнопки будет попеременно добавлять и удалять класс highlight у элемента div.
Проверка наличия классов
Метод contains() возвращает true, если элемент имеет указанный класс, и false в противном случае. Используйте его для ветвления по текущему состоянию, например для обновления метки кнопки.
Пример
<div id="containsClassExample" class="highlight">
This element's classes will be checked.
</div>
<button onclick="checkClass()">Check Class</button>
<script>
function checkClass() {
const element = document.getElementById('containsClassExample');
if (element.classList.contains('highlight')) {
alert('The element has the highlight class.');
} else {
alert('The element does not have the highlight class.');
}
}
</script>
<style>
.highlight {
background-color: yellow;
}
.text-large {
font-size: 24px;
}
</style>Здесь нажатие кнопки проверит, содержит ли элемент containsClassExample класс highlight, и отобразит соответствующее оповещение.
Замена класса
Метод replace() заменяет один класс другим за один вызов и возвращает true, если старый класс существовал и был заменён. Это чище, чем последовательный вызов remove() и add():
<div id="replaceClassExample" class="theme-light">Switch my theme.</div>
<button onclick="swapTheme()">Toggle theme</button>
<script>
function swapTheme() {
const element = document.getElementById('replaceClassExample');
if (!element.classList.replace('theme-light', 'theme-dark')) {
// It wasn't 'theme-light', so swap the other way.
element.classList.replace('theme-dark', 'theme-light');
}
}
</script>
<style>
.theme-light { background: #fff; color: #111; padding: 8px; }
.theme-dark { background: #111; color: #fff; padding: 8px; }
</style>classList также является итерируемым объектом, а classList.item(index) возвращает класс по заданному индексу (или null, если индекс выходит за пределы диапазона), что иногда полезно при необходимости перебирать классы по одному.
Реальный пример: интерактивный список задач
Для демонстрации этих концепций на практике создадим небольшой интерактивный список задач. Новые задачи добавляются в список, а нажатие на задачу переключает класс completed, который зачёркивает её текст — классический случай применения classList.toggle().
<div>
<h2>To-Do List</h2>
<p>Here, you can add new items, and mark it as completed by clicking on them.</p>
<input type="text" id="newTask" placeholder="Add a new task" />
<button id="addTaskButton">Add Task</button>
<ul id="taskList"></ul>
</div>
<script>
const newTaskInput = document.getElementById('newTask');
const addTaskButton = document.getElementById('addTaskButton');
const taskList = document.getElementById('taskList');
addTaskButton.addEventListener('click', () => {
const taskText = newTaskInput.value;
if (taskText) {
const taskItem = document.createElement('li');
taskItem.textContent = taskText;
taskItem.classList.add('task');
taskItem.addEventListener('click', () => {
taskItem.classList.toggle('completed');
});
taskList.appendChild(taskItem);
newTaskInput.value = '';
}
});
</script>
<style>
.task {
cursor: pointer;
padding: 5px;
border-bottom: 1px solid #ccc;
}
.task.completed {
text-decoration: line-through;
color: gray;
}
</style>В этом примере мы создаём приложение со списком задач, где задачи можно добавлять и отмечать как выполненные нажатием на них. Класс task стилизует задачи, а класс completed, применяемый с помощью метода toggle(), обозначает выполненные задачи.
Лучшие практики
Для обеспечения эффективного и удобного в сопровождении кода при работе со стилями в DOM учитывайте следующие рекомендации:
- Разделение ответственности: держите HTML, CSS и JavaScript раздельными. По возможности используйте JavaScript для управления классами, а не для прямой установки стилей. Этот подход поддерживает разделение ответственности и упрощает управление кодом.
- Избегайте инлайн-стилей: применяйте инлайн-стили умеренно. Инлайн-стили могут засорять HTML и усложнять его поддержку. Вместо этого предпочитайте добавление и удаление классов, определённых в CSS.
- Используйте классы для повторного использования: определяйте многократно используемые классы в CSS и применяйте JavaScript для их переключения. Этот подход обеспечивает более согласованную стилизацию в приложении и упрощает обновление стилей.
- Используйте методы
classList: применяйте методыclassList(add,remove,toggle,contains) для эффективного управления классами. Эти методы просты в использовании и работают лучше, чем прямое манипулирование свойствомclassName. - Соображения производительности: учитывайте производительность при манипуляции с DOM. Переключение одного класса запускает один пересчёт стилей, тогда как последовательная установка многих свойств через
element.styleможет вызывать многократные перекомпоновки. Для более подробного руководства см. Оптимизация производительности DOM.
Предпочитайте CSS-переходы и анимации циклам анимации на основе JavaScript. Переключите класс и дайте браузеру анимировать изменение — это выполняется на уровне компоновщика и обычно плавнее. Подробности см. в CSS-анимации.
Заключение
Манипуляция стилями в DOM необходима для создания динамических интерактивных интерфейсов. Используйте свойство style (и cssText) для значений, вычисляемых во время выполнения, getComputedStyle() для чтения стилей, фактически применённых браузером, и classList API — add, remove, toggle, contains, replace — для всего, что представляет многократно используемое состояние. Как правило, сначала обращайтесь к классам, а к инлайн-стилям только при необходимости.
Для дальнейшего изучения DOM ознакомьтесь с Манипуляцией DOM, Выбором элементов DOM и Атрибутами и свойствами.