Цветовой контраст

Библиотека Haunted предоставляет декларативный способ построения Web Components с использованием хуков, знакомых по React. Одним из практических аспектов разработки компонентов является корректная работа с цветом и контрастом, особенно в темах и пользовательских интерфейсах, чувствительных к доступности.

Основы контраста

Цветовой контраст определяет соотношение яркости переднего плана и фона. Для текстовых элементов это критично, так как недостаточный контраст снижает читабельность и нарушает требования доступности (WCAG). В среде Web Components стиль часто инкапсулирован внутри Shadow DOM, поэтому значение контраста необходимо контролировать непосредственно в компоненте или передавать из внешней темы.

Управление темами в Haunted

Haunted позволяет использовать хуки для хранения и обновления состояния цвета:

import { component, useState } from 'haunted';

function Colorful() {
  const [color, setColor] = useState('#000');
  const [background, setBackground] = useState('#fff');

  return html`
    <div style="color:${color}; background:${background}">
      Текст с динамическими цветами
    </div>
  `;
}

customElements.define('colorful-text', component(Colorful));

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

Вычисление контрастного коэффициента

Контрастный коэффициент может быть вычислен на основе относительной яркости цветов. Основой служит формула WCAG, использующая линейную яркость каждого канала RGB. Типичное решение — вынести вычисление в отдельную функцию, которую затем вызывать внутри рендера или эффекта:

function luminance(r, g, b) {
  const a = [r, g, b].map(v => {
    v = v / 255;
    return v <= 0.03928
      ? v / 12.92
      : Math.pow((v + 0.055) / 1.055, 2.4);
  });
  return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
}

function contrast(rgb1, rgb2) {
  const lum1 = luminance(...rgb1);
  const lum2 = luminance(...rgb2);
  const brightest = Math.max(lum1, lum2);
  const darkest = Math.min(lum1, lum2);
  return (brightest + 0.05) / (darkest + 0.05);
}

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

Автоматическая адаптация цвета

Хуки useEffect и useState позволяют адаптировать цвета в ответ на изменения пропсов или пользовательских действий. Например, при выборе фона компонент может автоматически подбирать подходящий текстовый цвет на основе контрастного коэффициента:

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

function AdaptiveText({ background }) {
  const [color, setColor] = useState('#000');

  useEffect(() => {
    const bg = hexToRgb(background);
    const whiteContrast = contrast(bg, [255, 255, 255]);
    const blackContrast = contrast(bg, [0, 0, 0]);
    setColor(whiteContrast >= blackContrast ? '#fff' : '#000');
  }, [background]);

  return html`
    <span style="color:${color}; background:${background}">
      Контрастный текст
    </span>
  `;
}

customElements.define('adaptive-text', component(AdaptiveText));

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

Поддержка пользовательских настроек и медиа-запросов

В интерфейсах, где присутствует возможность переключения тем, удобно сочетать Haunted с CSS Custom Properties. Shadow DOM позволяет безопасно принимать переменные от родителя и применять их внутри компонента. Через prefers-color-scheme браузер сообщает о предпочтениях темного или светлого режима, что также может служить триггером для перестроения палитры.

Контраст и доступность

Соблюдение минимального контраста повышает доступность интерфейсов и делает компоненты пригодными для реального применения. WCAG рекомендует коэффициент не ниже 4.5:1 для обычного текста и 3:1 для крупного. Использование автоматизированных вычислений в Haunted привносит улучшения в UX без увеличения сложности реализации.

Стилистические решения

Цветовой контраст может быть не только функциональным, но и эстетическим инструментом. За счет хуков можно экспериментировать с темами, трансформациями и анимациями, не теряя контроля над читаемостью. Так достигается гибкое сочетание дизайна и технических требований внутри одного веб-компонента.