Динамические стили

Haunted — это библиотека для создания веб-компонентов на основе функционального подхода, построенного поверх Web Components и Hooks, похожих на React. Одним из ключевых аспектов разработки компонентов является возможность динамически изменять стили элементов в зависимости от состояния или пропсов. Haunted предоставляет гибкие механизмы для этого, позволяя интегрировать CSS прямо в компоненты или использовать классические подходы с атрибутами class и style.


Инлайн-стили и реактивность

Инлайн-стили — это самый прямой способ управления внешним видом элемента. В Haunted стиль может зависеть от состояния, создаваемого с помощью useState или других хуков.

import { html, component, useState } from 'haunted';

function ColorBox() {
  const [active, setActive] = useState(false);

  const styles = `
    width: 100px;
    height: 100px;
    background-color: ${active ? 'green' : 'red'};
    transition: background-color 0.3s;
  `;

  return html`
    <div style="${styles}" @click="${() => setActive(!active)}"></div>
  `;
}

customElements.define('color-box', component(ColorBox));

Ключевые моменты:

  • Использование шаблонных литералов для динамических значений.
  • Реактивность состояния автоматически обновляет DOM при изменении переменной active.
  • Инлайн-стили удобны для небольших компонентов, но при масштабировании могут усложнять поддержку кода.

Классы и условная логика

Для более сложных компонентов лучше использовать динамические классы, управляемые состоянием. Haunted поддерживает синтаксис условного добавления классов через JavaScript.

import { html, component, useState } from 'haunted';

function Button() {
  const [pressed, setPressed] = useState(false);

  const className = pressed ? 'button pressed' : 'button';

  return html`
    <button class="${className}" @click="${() => setPressed(!pressed)}">
      Нажми меня
    </button>
  `;
}

customElements.define('dynamic-button', component(Button));
  • Классы позволяют отделить стили от логики компонента.
  • Можно комбинировать несколько состояний, создавая комплексные наборы классов:
const className = `button ${pressed ? 'pressed' : ''} ${disabled ? 'disabled' : ''}`;
  • Для управления большими списками классов удобно использовать утилиты вроде classnames или писать собственные функции.

Scoped CSS и <style> внутри компонента

Haunted поддерживает использование локальных стилей через тег <style> внутри шаблона компонента. Такой подход позволяет изолировать CSS и делает стили компонент-ориентированными.

function Card({ highlighted }) {
  return html`
    <style>
      .card {
        padding: 20px;
        border-radius: 8px;
        background-color: white;
        box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        transition: transform 0.2s;
      }
      .card.highlighted {
        transform: scale(1.05);
        box-shadow: 0 4px 10px rgba(0,0,0,0.2);
      }
    </style>
    <div class="card ${highlighted ? 'highlighted' : ''}">
      Контент карточки
    </div>
  `;
}
  • Все стили, определённые внутри шаблона, привязаны к компоненту и не затрагивают внешние элементы.
  • Комбинация классов с состоянием делает возможным создание анимаций и визуальных эффектов без внешних CSS-файлов.

Использование CSS-переменных

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

function ThemedBox({ color }) {
  return html`
    <style>
      .box {
        width: 150px;
        height: 150px;
        background-color: var(--box-color, gray);
        transition: background-color 0.3s;
      }
    </style>
    <div class="box" style="--box-color: ${color}"></div>
  `;
}
  • Позволяет легко передавать стили как параметры.
  • Хорошо сочетается с системами темизации.
  • CSS-переменные поддерживают наследование и упрощают управление сложными визуальными состояниями.

Анимации и переходы с динамическими стилями

Для динамических компонентов важно учитывать плавность переходов. Haunted не ограничивает стандартные CSS-анимации и transition:

function FadeBox() {
  const [visible, setVisible] = useState(true);

  return html`
    <style>
      .fade {
        opacity: ${visible ? 1 : 0};
        transition: opacity 0.5s;
        width: 100px;
        height: 100px;
        background-color: blue;
      }
    </style>
    <div class="fade"></div>
    <button @click="${() => setVisible(!visible)}">Toggle</button>
  `;
}
  • Реактивное состояние Haunted автоматически обновляет атрибуты и свойства стилей.
  • Можно комбинировать с классами и CSS-переменными для более сложных эффектов.

Практические советы

  • Использовать инлайн-стили для мелких, одноразовых изменений.
  • Для повторно используемых компонентов лучше применять классы и scoped <style>.
  • CSS-переменные позволяют легко менять тему или цветовую схему компонентов.
  • Состояния можно комбинировать через функции или утилиты, чтобы избежать громоздких выражений в шаблонах.
  • Для производительности стоит избегать слишком частых вычислений строк стилей в каждом рендере; лучше хранить результат в переменной или мемоизировать его через useMemo (или аналогичные подходы в Haunted).

Динамические стили в Haunted — это комбинация реактивных состояний, классов, CSS-переменных и scoped CSS, позволяющая создавать визуально богатые и гибкие веб-компоненты без глобального загрязнения стилей.