Стилизация заблокированных дат

В календаре Pikaday каждая дата может находиться в нескольких состояниях: активная, выбранная, вне диапазона или заблокированная. Заблокированные даты (disabled dates) представляют собой элементы, которые визуально присутствуют в календаре, но не участвуют в выборе и не реагируют на пользовательские действия. Их корректная стилизация критична для UX, так как именно визуальное оформление определяет различие между доступными и недоступными значениями.

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

  • is-disabled

Дополнительно могут применяться контекстные классы, такие как:

  • is-outside-current-month — даты соседних месяцев
  • is-selected — выбранная дата (если не пересекается с disabled логикой)
  • is-today — текущий день

Состояние disabled всегда имеет приоритет над визуальными маркерами выбора.


Механизм назначения disabled-состояния

Блокировка дат в Pikaday реализуется через конфигурацию disable и колбэки логики:

new Pikaday({
    field: document.querySelector('#date'),
    disableDayFn: function (date) {
        return date.getDay() === 0; // блокировка воскресений
    }
});

При возврате true из disableDayFn дата получает класс is-disabled.

Также используется массив дат:

disable: [
    new Date(2026, 0, 1),
    new Date(2026, 0, 2)
]

В этом случае совпадающие даты автоматически получают статус disabled.


Базовая стилизация disabled-дней

CSS-уровень отвечает за визуальное отделение недоступных дат от активных. Основной селектор:

.pika-button.is-disabled {
    color: #b5b5b5;
    cursor: default;
    opacity: 0.4;
    pointer-events: none;
}

Ключевые элементы поведения:

  • color снижает контраст текста
  • opacity визуально «гасит» элемент
  • cursor: default убирает интерактивный указатель
  • pointer-events: none предотвращает любые клики

Важно учитывать, что Pikaday уже частично блокирует события на уровне JavaScript, но CSS-дублирование усиливает предсказуемость интерфейса.


Разделение состояний: disabled vs outside-month

Одной из частых ошибок является конфликт визуальных состояний. Даты соседних месяцев также могут выглядеть «неактивными», но они не всегда заблокированы логически.

Рекомендуемая дифференциация:

.pika-button.is-outside-current-month {
    color: #d0d0d0;
    opacity: 0.5;
}

И отдельно:

.pika-button.is-disabled {
    color: #9e9e9e;
    background: transparent;
    text-decoration: line-through;
}

Использование text-decoration: line-through усиливает семантическое различие между «неактуальной датой» и «недоступной датой».


Приоритетность состояний и каскад стилей

Pikaday может одновременно применять несколько классов к одному элементу. Например:

<td class="is-disabled is-today">

В таких случаях важно определить приоритет визуализации. Обычно disabled имеет наивысший приоритет.

Рекомендуемый порядок переопределений:

.pika-button.is-disabled {
    opacity: 0.35;
    color: #c2c2c2;
    background: none;
}

.pika-button.is-disabled.is-today {
    border: 1px solid #e0e0e0;
}

Даже если дата является текущей, блокировка должна визуально доминировать над акцентом today.


Кастомизация через темы

Стилизация disabled-состояний часто интегрируется в общую тему календаря.

Пример тематической системы:

:root {
    --pika-disabled-color: #a8a8a8;
    --pika-disabled-bg: transparent;
    --pika-disabled-opacity: 0.3;
}

Применение:

.pika-button.is-disabled {
    color: var(--pika-disabled-color);
    background: var(--pika-disabled-bg);
    opacity: var(--pika-disabled-opacity);
}

Такой подход позволяет централизованно управлять визуальной доступностью компонентов без изменения логики библиотеки.


Стилизация hover и предотвращение визуальных артефактов

Хотя disabled-элементы не должны реагировать на hover, браузеры иногда применяют псевдокласс :hover даже при pointer-events: none в родительских элементах.

Для устранения побочных эффектов:

.pika-button.is-disabled:hover {
    background: transparent;
    color: #b5b5b5;
    box-shadow: none;
}

Это предотвращает «подсветку» заблокированных дат при движении курсора.


Границы доступных диапазонов и визуальная сегментация

При использовании ограничений minDate и maxDate формируется естественная группа disabled-дней за пределами диапазона.

Стилизация часто дополняется визуальным разделением:

.pika-prev.is-disabled,
.pika-next.is-disabled {
    opacity: 0.2;
    cursor: default;
}

Аналогичный подход применяется к кнопкам навигации, когда переход за пределы календарного диапазона невозможен.


Интеграция с фокус-стилями

При навигации с клавиатуры disabled-элементы не должны получать фокус. Однако в кастомных темах важно гарантировать отсутствие outline:

.pika-button.is-disabled:focus {
    outline: none;
}

Это предотвращает визуальные аномалии при программной навигации.


Сложные сценарии: динамическая блокировка

При изменении состояния календаря во время работы приложения (например, загрузка занятых дат с сервера) disabled-состояния могут обновляться динамически.

В таких случаях важна синхронизация DOM-обновлений:

picker.setDate(new Date());
picker.draw(true);

После перерисовки элементы заново получают классы, включая is-disabled, что требует корректной работы CSS без зависимости от статических состояний.


Визуальная иерархия disabled-элементов

При проектировании интерфейса календаря важно учитывать, что disabled-даты не должны конкурировать с активными элементами. Их роль — фоновая информационная структура.

Рекомендуемая визуальная иерархия:

  • активные даты: насыщенный цвет, hover-эффекты
  • выбранная дата: акцентный фон
  • текущая дата: рамка или маркер
  • заблокированные даты: низкий контраст, отсутствие интерактивности

Совместимость кастомных стилей с обновлениями Pikaday

При расширении базовых стилей важно избегать жесткой привязки к внутренним структурам DOM. Основная опора — классы:

  • is-disabled
  • pika-button
  • pika-table

Избыточная селекторная вложенность может привести к поломке при обновлении версии библиотеки. Оптимальная стратегия — минимально специфичные селекторы с приоритетом на классы состояния.


Поведение при комбинированных ограничениях

При одновременном использовании disableDayFn, minDate, maxDate и ручного массива disable итоговое состояние формируется как логическое объединение всех правил. С точки зрения визуализации это не требует дополнительных условий: любой источник блокировки приводит к единому классу is-disabled.

Это обеспечивает предсказуемую модель стилизации, где CSS не обязан различать источник ограничения.