Оформление: веб-компоненты

Справочник по оформлению покрывает полный каталог CSS-переменных. Этот документ описывает, как веб-компонент получает тему через shadow DOM.


Как тема доходит до вашего компонента

Shadow DOM блокирует каскад CSS — таблицы стилей, написанные вне вашего компонента, внутри него не действуют. Однако пользовательские CSS-свойства (переменные) границу shadow DOM пересекают. Это означает:

  • Пользовательские свойства наследуются через границу shadow DOM. WippyElement также пробрасывает каждое настроенное имя переменной через свой внутренний корень с принудительной темой, поэтому локально загруженные умолчания theme-config.css не могут сбросить настроенные значения.
  • Стили компонентов PrimeVue, утилиты Tailwind и другие таблицы стилей на основе правил не каскадируются внутрь — их нужно явно загружать через hostCssKeys.

Уровни настройки

L1 — Глобальный: пользовательские CSS-свойства пересекают границу shadow DOM. WippyElement перечисляет действующие карты переменных global/children/page, включая @light / @dark, и устанавливает универсальный мост наследования до слоя вставляемого пользовательского CSS.

L2 — Ограниченная область: то же, что L1, для пользовательских свойств. CSS на основе таблиц стилей (PrimeVue, Tailwind) не каскадируется — используйте hostCssKeys, чтобы явно загрузить их в shadow root.

L3 — config_overrides на уровне страницы: CSS-переменные, заданные оператором через config_overrides, доходят до хоста веб-компонента и внутреннего корня темы через тот же универсальный мост.

custom_css фасада доходит до shadow root (Web Host 1.0.43+, с возможностью отключения). Правила с селекторами не каскадируются через границу, поэтому среда выполнения вставляет составленный пользовательский CSS global + children.

Мост настроенных переменных не зависит от фронтенд-отключения customCss и остаётся активным. Порядок: платформенные умолчания темы → мост наследования настроенных переменных → вставленный пользовательский CSS.

До Web Host 1.0.43 правила custom_css фасада не доходили до shadow root компонента — наследовались только пользовательские свойства. На более старых хостах повторите правило внутри собственных стилей веб-компонента или переведите его в форму токена --p-*.


Получение CSS темы

Вынесение JavaScript во внешние зависимости следует полному зафиксированному import-map.json Web Host, в том числе для @wippy-fe/theme. Доставка CSS устроена иначе: shadow root получает ресурсы темы на основе правил только через hostCssKeys либо через включённый в бандл/встроенный CSS.

hostCssKeys — загрузка CSS во время выполнения

Объявите, какие раздаваемые хостом CSS-ресурсы среда выполнения веб-компонента должна вставить в ваш shadow root. Добавьте их в wippyConfig.hostCssKeys:

static get wippyConfig(): WippyElementConfig<ComponentProps> {
  return {
    propsSchema: pkg.wippy.props as WippyPropsSchema,
    hostCssKeys: ['themeConfigUrl', 'iframeCssUrl'] as const,
    inlineCss: stylesText,
  }
}
Ключ Что загружает Размер Когда включать
themeConfigUrl theme-config.css — полная система CSS-переменных --p-* ~8 КБ Когда веб-компонент потребляет семантические токены хоста, тёмный режим или оформленную оболочку. Нейтральный по представлению canvas/SVG/график может обойтись без него.
primeVueCssUrl Весь CSS компонентов PrimeVue (режим unstyled) ~455 КБ Только если веб-компонент отрисовывает компоненты PrimeVue (<Button>, <Dialog> и т. д.) внутри своего shadow root.
markdownCssUrl Стили markdown для .data-body ~5 КБ Только если веб-компонент отрисовывает markdown-содержимое.
iframeCssUrl Оформление полос прокрутки по теме по умолчанию; имя историческое ~1 КБ Обязателен для любого веб-компонента, который может прокручиваться, ради единообразия полос прокрутки.

preflightCssUrl не входит в объединение HostCssKey. Если вам действительно нужен preflight Tailwind v3 внутри shadow root, вызовите hostCss.preflightCssUrl + loadCss() императивно. На практике это требуется редко.

Рекомендации по размеру бандла

hostCssKeys Всего подтягивается CSS
['themeConfigUrl'] ~8 КБ
['themeConfigUrl', 'iframeCssUrl'] ~9 КБ
['themeConfigUrl', 'markdownCssUrl', 'iframeCssUrl'] ~14 КБ
['themeConfigUrl', 'primeVueCssUrl', 'iframeCssUrl'] ~464 КБ

Выбирайте независимо:

  • Нейтральный по представлению canvas/SVG/график без стандартных продуктовых элементов управления, семантических токенов хоста и утилитарных классов может обойтись без PrimeVue, ресурса темы и Tailwind.
  • Любая кнопка, поле ввода, форма, таблица, диалог, меню, тег, подсказка или элемент обратной связи требует эквивалента из PrimeVue, PrimeVuePlugin и primeVueCssUrl.
  • Семантические токены хоста, тёмный режим или оформленная оболочка требуют themeConfigUrl.
  • Tailwind нужен, когда исходный код использует утилитарные классы Tailwind.
  • Прокручиваемое содержимое требует iframeCssUrl.

inlineCss — CSS времени сборки

Скомпилируйте свой Tailwind/SCSS во время сборки и вставьте его в shadow root через inlineCss. Используйте импорт Vite ?inline:

import stylesText from './styles.css?inline'

static get wippyConfig() {
  return {
    hostCssKeys: ['themeConfigUrl'] as const,
    inlineCss: stylesText,
  }
}

Запасной вариант для локальной разработки

Для локальной разработки без хоста импортируйте theme-config.css прямо в свой styles.css, чтобы получить запасные значения переменных:

/* src/styles.css */
@import "@wippy-fe/theme/theme-config.css";

:host {
  color: var(--p-text-color);
  background: var(--p-content-background);
}

Это даёт значения --p-* по умолчанию, так что ваш компонент корректно отображается в host-less-режиме. Во время выполнения настоящая тема доставляется через hostCssKeys: ['themeConfigUrl'] и имеет приоритет.


Написание CSS компонента

Запрашивайте themeConfigUrl, потребляйте семантические переменные и не переобъявляйте унаследованные умолчания палитры. Семантические алиасы переключаются в режиме Auto и в принудительных режимах:

:host {
  color: var(--p-text-color);
  background: var(--p-content-background);
  border: 1px solid var(--p-content-border-color);
}

.danger-indicator {
  color: var(--p-danger-500);
}

Не используйте var(--p-surface-N) для цветов, зависящих от темы — нумерованная шкала surface не переключается в тёмном режиме. Вместо этого используйте семантические алиасы (--p-text-color, --p-content-background, --p-text-muted-color, --p-content-border-color).

Для производных оттенков: color-mix(in srgb, var(--p-content-background) 85%, var(--p-text-color) 15%).

Защитные запасные значения

Веб-компоненты могут работать в host-less dev-режиме (без родительской страницы), поэтому запасное значение допустимо:

/* Допустимо в веб-компонентах — только как запасной вариант для dev-просмотра */
color: var(--p-text-color, #404040);

Ограничьтесь одним запасным значением на логический цвет, помечайте их как "только для dev-просмотра" и никогда не используйте их в микрофронтенд-приложениях (там переменные всегда предоставляет хост).

Чтение переменных в JS

При передаче значений темы в контексты вне CSS (D3, Canvas, mermaid):

const styles = getComputedStyle(this.$el)
const primaryColor = styles.getPropertyValue('--p-primary-500').trim()
const background = styles.getPropertyValue('--p-content-background').trim()
// передайте в mermaid.init или D3.scaleOrdinal

Типичные шаблоны

// Нейтральный по представлению веб-компонент только с графиком: без элементов управления, токенов хоста, утилит и прокрутки:
hostCssKeys: [] as const

// Веб-компонент, отрисовывающий компоненты PrimeVue внутри Shadow DOM:
hostCssKeys: ['themeConfigUrl', 'primeVueCssUrl', 'iframeCssUrl'] as const

// Веб-компонент, отрисовывающий markdown:
hostCssKeys: ['themeConfigUrl', 'markdownCssUrl', 'iframeCssUrl'] as const

// Пример: веб-компонент mermaid — отрисовывает SVG напрямую, нужны только переменные --p-*:
hostCssKeys: ['themeConfigUrl'] as const

Антипаттерны, специфичные для веб-компонентов

  • Зашитые hex-значения внутри :host { … } — вместо этого используйте var(--p-*).
  • Блоки <style> с @media (prefers-color-scheme: dark), зашивающие цвета тёмного режима — переменные в theme-config.css сами перенастраиваются под тёмную тему; если вы корректно ссылаетесь на var(--p-*), тёмный режим достаётся бесплатно.
  • Запрос primeVueCssUrl, когда веб-компонент не отрисовывает PrimeVue — добавляет большую таблицу стилей без всякой пользы.
  • Установка appendTo: 'self' для оверлеев PrimeVue как рутинного решения. Установите PrimeVuePlugin и оставьте цель по умолчанию; она перенаправляет на закреплённый оверлейный слой во владеющем shadow root. Явный self — это инлайн-размещение, которое может обрезаться в прокручиваемых оверлеях.
  • Забытые bubbles: true, composed: true при диспетчеризации CustomEvent — события не выйдут за пределы shadow DOM.
  • Решение о вынесении @wippy-fe/theme во внешние зависимости на основе предположений о CSS вместо полной зафиксированной import map Web Host.

Проверка

Не останавливайтесь на непустом токене. Сравните точное настроенное значение на хосте элемента и во внутреннем корне темы, затем проверьте разрешённый браузером цвет, используемый отрисованным элементом управления:

const el = document.querySelector('your-element')
const inner = el.shadowRoot.querySelector('[data-wippy-theme-root]')
getComputedStyle(el).getPropertyValue('--p-primary-color')
getComputedStyle(inner).getPropertyValue('--p-primary-color')

Повторите для каждого настроенного семейства в режимах Auto-light, Auto-dark, принудительный Light и принудительный Dark. Веб-компонент запрашивает themeConfigUrl и потребляет семантические токены; он не переобъявляет унаследованные умолчания палитры.

Полный порядок отладки: Отладка.


Связанные документы

  • theming.md — каталог CSS-переменных и антипаттерны
  • micro-frontend-app-theming.md — оформление микрофронтенд-приложений (инъекция в iframe)
  • web-component.md — полное руководство по разработке веб-компонентов
  • host-less-mode.md — dev-оверлей и host-less-режим
  • compliance-checklist.md — полные правила REJECT/WARN для оформления