Создание собственных тем

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

Ключевой элемент архитектуры — минималистичная DOM-структура:

  • контейнер с классом awesomplete
  • выпадающий список с тегом ul
  • элементы списка li
  • состояния элементов: active, selected
  • дополнительные маркеры внутри элементов, например mark для подсветки совпадений

Именно эти классы становятся точками входа для любой кастомной темы.


Базовые классы и их роль в визуализации

Awesomplete использует фиксированный набор классов, которые можно считать контрактом между логикой и внешним видом:

.awesomplete {
    position: relative;
    display: inline-block;
}

.awesomplete > ul {
    position: absolute;
    left: 0;
    z-index: 1000;
    min-width: 100%;
    list-style: none;
    margin: 0;
    padding: 0;
}

.awesomplete > ul > li {
    padding: 8px 12px;
    cursor: pointer;
}

Состояние активного элемента:

.awesomplete > ul > li[aria-selected="true"],
.awesomplete > ul > li.active {
    background: #2684ff;
    color: #fff;
}

Подсветка совпадений:

.awesomplete mark {
    background: transparent;
    font-weight: 600;
}

Смысл темизации заключается в полном переопределении этих базовых правил.


Стратегии создания темы

Существует несколько устойчивых подходов к созданию кастомного оформления:

  1. Полное переопределение базовых классов
  2. Наследование и расширение существующих стилей
  3. Изоляция темы через дополнительный класс-обёртку
  4. Использование CSS-переменных для динамической настройки

Каждый подход влияет на масштабируемость и предсказуемость внешнего вида.


Темизация через дополнительный класс-обёртку

Наиболее устойчивый метод — добавление собственного класса к контейнеру:

<input class="awesomplete theme-dark" />

Дальнейшее стилизование строится вокруг пространства имён:

.theme-dark.awesomplete > ul {
    background: #1e1e1e;
    color: #eaeaea;
    border: 1px solid #333;
    border-radius: 6px;
}

.theme-dark.awesomplete > ul > li {
    padding: 10px 14px;
}

.theme-dark.awesomplete > ul > li:hover {
    background: #333;
}

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


Использование CSS-переменных для динамических тем

CSS-переменные позволяют отделить цветовую схему от структуры стилей:

.awesomplete {
    --bg: #ffffff;
    --text: #222;
    --hover: #f2f2f2;
    --active: #2684ff;
}

.awesomplete > ul {
    background: var(--bg);
    color: var(--text);
}

.awesomplete > ul > li:hover {
    background: var(--hover);
}

.awesomplete > ul > li.active {
    background: var(--active);
    color: #fff;
}

Изменение темы сводится к переопределению переменных:

.theme-dark {
    --bg: #1b1b1b;
    --text: #e0e0e0;
    --hover: #2a2a2a;
    --active: #4c8dff;
}

Темизация состояния активного элемента

Состояние навигации по списку играет ключевую роль в UX, поэтому его оформление обычно выделяется отдельно:

.awesomplete > ul > li.active {
    transform: translateX(2px);
    transition: all 0.15s ease;
}

Дополнительные визуальные индикаторы:

.awesomplete > ul > li.active::before {
    content: "";
    position: absolute;
    left: 0;
    width: 3px;
    height: 100%;
    background: #2684ff;
}

Такой приём создаёт акцент без изменения структуры DOM.


Стилизация подсветки совпадений

Awesomplete автоматически оборачивает совпавшие фрагменты в тег mark. Это позволяет полностью контролировать акцентирование текста:

.awesomplete mark {
    background: none;
    color: inherit;
    border-bottom: 2px solid #ffcc00;
}

Альтернативный вариант с более агрессивным выделением:

.awesomplete mark {
    background: #fff3a0;
    padding: 0 2px;
    border-radius: 2px;
}

Компактные и расширенные темы

Различные сценарии интерфейса требуют разных плотностей отображения.

Компактный вариант:

.theme-compact.awesomplete > ul > li {
    padding: 4px 8px;
    font-size: 13px;
}

Расширенный вариант:

.theme-spacious.awesomplete > ul > li {
    padding: 14px 18px;
    font-size: 16px;
}

Регулировка плотности часто важнее цветовой схемы в интерфейсах с высокой частотой ввода.


Добавление визуальной иерархии

Темы могут включать дополнительную структуру внутри элементов списка:

.awesomplete .subtitle {
    display: block;
    font-size: 12px;
    opacity: 0.6;
}

HTML-структура при кастомном рендеринге:

<li>
    Основной текст
    <span class="subtitle">дополнительное описание</span>
</li>

Такая иерархия особенно полезна при автодополнении с API-данными.


Анимационные темы

Плавное появление списка улучшает восприятие интерфейса:

.awesomplete > ul {
    opacity: 0;
    transform: translateY(4px);
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.awesomplete[aria-expanded="true"] > ul {
    opacity: 1;
    transform: translateY(0);
}

Дополнительная анимация элементов:

.awesomplete > ul > li {
    transition: background 0.1s ease, padding-left 0.1s ease;
}

.awesomplete > ul > li:hover {
    padding-left: 16px;
}

Темы с иконками и визуальными маркерами

Расширение темы часто включает добавление декоративных элементов:

.awesomplete > ul > li::before {
    content: "›";
    margin-right: 8px;
    opacity: 0.5;
}

Или использование SVG-фона:

.awesomplete > ul > li {
    background-image: url("icon.svg");
    background-repeat: no-repeat;
    background-position: 8px center;
    padding-left: 32px;
}

Интеграция тем с состояниями доступности

Awesomplete активно использует ARIA-атрибуты, которые также могут участвовать в стилизации:

.awesomplete > ul[hidden] {
    display: none;
}

.awesomplete > ul[aria-hidden="true"] {
    opacity: 0;
}

Состояние фокуса:

.awesomplete input:focus {
    outline: 2px solid #2684ff;
    outline-offset: 2px;
}

Темы с полной заменой визуального поведения

В отдельных случаях базовая стилизация полностью отключается:

.awesomplete > ul {
    all: unset;
    position: absolute;
    width: 100%;
}

Далее строится полностью новая визуальная система поверх минимальной структуры:

.awesomplete > ul > li {
    display: flex;
    justify-content: space-between;
    padding: 10px;
    background: #fff;
    border-bottom: 1px solid #eee;
}

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


Многослойные темы и контекстное оформление

Темизация может зависеть от окружения компонента:

.form-dark .awesomplete > ul {
    background: #111;
    color: #ddd;
}

.form-light .awesomplete > ul {
    background: #fff;
    color: #111;
}

Контекстный подход позволяет использовать один и тот же компонент в разных разделах интерфейса без модификации JavaScript.


Поведенчески-зависимая стилизация

Некоторые стили зависят от динамического состояния списка:

.awesomplete[aria-expanded="true"] input {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}

Или визуальная связь с количеством элементов:

.awesomplete > ul:empty {
    display: none;
}

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