CSS-переменные в компонентах

Slim.js позволяет создавать лёгкие веб-компоненты с минимальной зависимостью от сторонних библиотек, сохраняя при этом высокую динамичность и реактивность. Одним из мощных инструментов стилизации в современных веб-компонентах являются CSS-переменные (custom properties). Они позволяют управлять внешним видом компонентов без необходимости вмешательства в сам код компонента, обеспечивая гибкость и переиспользуемость стилей.

Объявление и использование CSS-переменных

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

:root {
  --primary-color: #3498db;
  --secondary-color: #2ecc71;
}

В компоненте Slim.js их можно использовать в стилях напрямую:

import { Slim } from 'slim-js';

export default class MyButton extends Slim {
  get template() {
    return `
      <style>
        button {
          background-color: var(--primary-color);
          color: white;
          border: none;
          padding: 10px 20px;
          cursor: pointer;
          transition: background-color 0.3s ease;
        }

        button:hover {
          background-color: var(--secondary-color);
        }
      </style>
      <button><slot></slot></button>
    `;
  }
}

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

Использование var(--имя-переменной) позволяет компоненту автоматически адаптироваться к любым изменениям значений переменных, заданных на уровне страницы или родительских компонентов.

Локальные CSS-переменные в компонентах

Для ограничения действия переменной только внутри компонента её можно объявлять внутри селектора корня компонента:

get template() {
  return `
    <style>
      :host {
        --button-radius: 12px;
      }

      button {
        border-radius: var(--button-radius);
      }
    </style>
    <button><slot></slot></button>
  `;
}

:host представляет сам компонент, и переменные, объявленные здесь, доступны только внутри него. Это позволяет создавать независимые стили без влияния на глобальный стиль страницы.

Динамическое обновление CSS-переменных

Slim.js позволяет динамически изменять значения CSS-переменных через JavaScript, используя style.setProperty:

this.style.setProperty('--primary-color', '#e74c3c');

Применение этой команды внутри методов жизненного цикла компонента (onBeforeRender, onAfterRender) позволяет изменять внешний вид компонента в ответ на события или свойства.

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

Компоненты Slim.js легко интегрируются с CSS-переменными, определёнными на уровне родительских элементов или глобальных стилей. Например:

<div style="--primary-color: purple;">
  <my-button>Клик</my-button>
</div>

В этом случае кнопка внутри my-button автоматически наследует цвет purple без дополнительных изменений в компоненте. Наследование происходит через стандартный механизм CSS, что делает компоненты гибкими для повторного использования.

Переопределение и каскадирование переменных

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

get template() {
  return `
    <style>
      :host {
        --button-bg: var(--primary-color, #3498db);
        --button-text: white;
      }

      button {
        background-color: var(--button-bg);
        color: var(--button-text);
      }
    </style>
    <button><slot></slot></button>
  `;
}

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

Взаимодействие CSS-переменных с реактивными свойствами Slim.js

Slim.js поддерживает реактивные свойства компонентов, которые можно синхронизировать с CSS-переменными:

export default class ColorButton extends Slim {
  static get observedAttributes() { return ['color']; }

  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'color') {
      this.style.setProperty('--button-bg', newValue);
    }
  }

  get template() {
    return `
      <style>
        button {
          background-color: var(--button-bg, #3498db);
          color: white;
          padding: 10px 15px;
          border: none;
          border-radius: 8px;
        }
      </style>
      <button><slot></slot></button>
    `;
  }
}

customElements.define('color-button', ColorButton);

Изменение атрибута color автоматически обновляет переменную --button-bg, что приводит к динамическому изменению цвета кнопки без необходимости перерендеривания всего компонента.

Советы по организации стилей с CSS-переменными

  1. Использовать имена переменных с префиксом компонента для предотвращения конфликтов: --my-button-bg, --my-button-radius.
  2. Определять значения по умолчанию для всех переменных внутри компонента через var(--имя, default).
  3. Группировать связанные переменные (цвета, размеры, отступы) в одном блоке для удобства поддержки.
  4. Совмещать переменные с медиа-запросами для адаптивного дизайна компонентов:
:host {
  --button-padding: 10px 20px;
}

@media (max-width: 600px) {
  :host {
    --button-padding: 8px 16px;
  }
}

button {
  padding: var(--button-padding);
}

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

Итоговая структура компонента с CSS-переменными

Полностью подготовленный компонент может содержать глобальные и локальные переменные, реактивные свойства и адаптивные настройки:

export default class AdaptiveButton extends Slim {
  static get observedAttributes() { return ['color']; }

  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'color') {
      this.style.setProperty('--button-bg', newValue);
    }
  }

  get template() {
    return `
      <style>
        :host {
          --button-bg: var(--primary-color, #3498db);
          --button-radius: 10px;
          --button-padding: 12px 24px;
        }

        @media (max-width: 500px) {
          :host {
            --button-padding: 10px 20px;
          }
        }

        button {
          background-color: var(--button-bg);
          border-radius: var(--button-radius);
          padding: var(--button-padding);
          color: white;
          border: none;
          cursor: pointer;
          transition: background-color 0.3s ease;
        }

        button:hover {
          filter: brightness(90%);
        }
      </style>
      <button><slot></slot></button>
    `;
  }
}

customElements.define('adaptive-button', AdaptiveButton);

Этот компонент демонстрирует сочетание реактивности, гибкой настройки и адаптивного дизайна с использованием CSS-переменных, делая Slim.js эффективным инструментом для современного фронтенд-разработки.