CSS-классы как состояние интерфейса: преимущества и ограничения

Два вида карточек интерфейса с одним переключателем состояния

CSS-класс удобно отражает состояние интерфейса, но не обязан быть единственным хранилищем логики. В маленьком компоненте возможны оба подхода. Важно не создавать две независимые версии истины, когда класс показывает одно, переменная другое, а ARIA третье. Разберём управляемый компактный вид.

Переключатель вида с согласованным состоянием

index.html

<!doctype html>
<html lang="ru"><meta charset="utf-8"><title>Состояние карточек</title>
<style>.cards { display: grid; gap: 1rem; } .cards.is-compact { gap: .25rem; }
.cards p { padding: 1rem; border: 1px solid #555; } .cards.is-compact p { padding: .25rem; }</style>
<button id="toggle" type="button" aria-pressed="false">Компактные карточки</button>
<section class="cards"><p>Первая карточка</p><p>Вторая карточка</p></section>
<script>
let compact = false;
const button = document.querySelector('#toggle');
const cards = document.querySelector('.cards');
function render() {
  cards.classList.toggle('is-compact', compact);
  button.setAttribute('aria-pressed', String(compact));
}
button.addEventListener('click', () => { compact = !compact; render(); });
render();
</script></html>

В примере compact — источник состояния. render одним вызовом согласует визуальный класс и aria-pressed. Кнопка остаётся той же кнопкой, а её состояние переключения меняется. Это не раскрытие скрытой области, поэтому здесь не используется aria-expanded. CSS управляет расстояниями, а не принимает решения о доступе или бизнес-правилах.

Где хранить значение
Что сравнить На что смотреть Что сделать
Один простой переключатель Состояние можно явно читать из одного места Не дублировать несогласованно
Несколько связанных контролов Нужна общая модель Обновлять представление через одну функцию
Серверные данные Класс только отображает результат Не доверять DOM как подтверждению операции
Временная анимация Визуальное состояние может быть отдельным Не путать его с фактом завершения задачи

classList.toggle с вторым аргументом выражает намерение

Вызов без второго аргумента просто меняет текущее наличие класса. В render это опасно: два вызова могут вернуть прежний вид. Аргумент compact задаёт требуемое состояние, поэтому повторный render не должен менять результат. Такое свойство облегчает восстановление интерфейса после других обновлений.

  • Дважды вызвать render без изменения compact.
  • Проверить согласованность класса и aria-pressed.
  • Переключить кнопкой с клавиатуры.
  • Не использовать наличие класса как разрешение серверной операции.

Если компонент усложняется, не превращайте названия классов в неформальную базу данных. Отдельно храните выбранные значения, статус загрузки и ошибки, а классы вычисляйте из них. При этом для статичного декоративного эффекта отдельное хранилище может быть лишним. Архитектура должна соответствовать числу реальных зависимостей, а не моде.

Вопросы и ответы

Можно ли читать состояние через contains?

Да, если это осознанный единственный источник простого компонента. Проблема возникает при параллельной несогласованной модели.

Почему не менять style напрямую?

Класс собирает оформление в CSS и отделяет его от логики. Прямое изменение отдельных свойств иногда уместно, но требует ясной причины.

Нужна ли библиотека состояния?

Для одного boolean нет очевидной необходимости. Решение зависит от реальной сложности приложения.

Сохраняется ли режим после обновления?

В этом примере нет. Хранение настройки — отдельный слой с чтением, проверкой и обработкой ошибок.

Похожие записи