Система тем в Polymer

Система тем в Polymer предназначена для упрощения управления внешним видом компонентов через декларативное определение переменных CSS и их каскадное наследование. Она позволяет создавать гибкие, настраиваемые и повторно используемые элементы пользовательского интерфейса.

Определение тем

В основе системы лежит концепция CSS-переменных (custom properties). Polymer использует их для объявления и передачи значений стилей в компоненты:

:root {
  --primary-color: #4285f4;
  --secondary-color: #ea4335;
  --button-radius: 4px;
}

Эти переменные можно использовать внутри стилей компонентов с помощью функции var():

.my-button {
  background-color: var(--primary-color);
  border-radius: var(--button-radius);
}

Темы для компонентов

Polymer предоставляет механизм темизации компонентов, который позволяет каждому элементу иметь собственный набор переменных:

import { PolymerElement, html, css } from '@polymer/polymer';

class MyButton extends PolymerElement {
  static styles = css`
    :host {
      display: inline-block;
    }
    button {
      background-color: var(--my-button-background, #007bff);
      color: var(--my-button-color, #ffffff);
      border-radius: var(--my-button-radius, 4px);
      padding: 0.5em 1em;
      border: none;
      cursor: pointer;
    }
  `;

  static template = html`
    <button><slot></slot></button>
  `;
}

customElements.define('my-button', MyButton);

В данном примере для кнопки объявлены переменные --my-button-background, --my-button-color, --my-button-radius с значениями по умолчанию. Любой потребитель компонента может переопределить эти значения:

<style>
  my-button {
    --my-button-background: #28a745;
    --my-button-color: #ffffff;
    --my-button-radius: 8px;
  }
</style>

<my-button>Сохранить</my-button>

Наследование и каскадирование тем

Переменные в Polymer наследуются через DOM-иерархию. Это означает, что родительский элемент может задавать значения переменных, которые автоматически распространяются на вложенные компоненты:

<style>
  :root {
    --theme-primary-color: #ff9800;
  }

  my-card {
    --card-background: var(--theme-primary-color);
  }
</style>

<my-card>Контент карточки</my-card>

Если внутри my-card используется var(--card-background), она получит значение #ff9800. Если переменная не определена, используется значение по умолчанию, указанное в компоненте.

Использование styleModules

Polymer поддерживает модули стилей (styleModules) для переиспользования набора переменных и стилей между компонентами:

<dom-module id="shared-styles">
  <template>
    <style>
      :host {
        --shared-padding: 16px;
        --shared-font-size: 14px;
      }
    </style>
  </template>
</dom-module>

Затем эти стили подключаются к компоненту:

import { PolymerElement, html } from '@polymer/polymer';
import '@polymer/polymer/lib/elements/dom-module.js';

class MyCard extends PolymerElement {
  static template = html`
    <style include="shared-styles">
      :host {
        display: block;
        padding: var(--shared-padding);
        font-size: var(--shared-font-size);
        background-color: var(--card-background, #ffffff);
        border-radius: 8px;
        box-shadow: 0 2px 4px rgba(0,0,0,0.1);
      }
    </style>
    <slot></slot>
  `;
}

customElements.define('my-card', MyCard);

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

Темы и динамическое обновление

Polymer позволяет изменять значения переменных в рантайме, что дает возможность динамически переключать темы:

document.documentElement.style.setProperty('--primary-color', '#ff5722');

Все компоненты, использующие var(--primary-color), автоматически обновят свои стили без перерисовки и пересоздания элементов.

Лучшие практики

  • Для переиспользуемых компонентов рекомендуется задавать переменные с префиксом имени компонента (--my-button-color) для предотвращения конфликтов.
  • Для глобальных тем лучше использовать переменные на уровне :root или контейнера приложения.
  • По возможности задавать значения по умолчанию внутри компонентов, чтобы их можно было использовать независимо от глобальной темы.
  • Использовать styleModules для группировки связанных переменных и общих стилей.

Поддержка мультитем

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

<dom-module id="dark-theme">
  <template>
    <style>
      :host {
        --background-color: #121212;
        --text-color: #ffffff;
      }
    </style>
  </template>
</dom-module>

<dom-module id="light-theme">
  <template>
    <style>
      :host {
        --background-color: #ffffff;
        --text-color: #000000;
      }
    </style>
  </template>
</dom-module>

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