Scoped стили

Scoped стили — это механизм, который позволяет ограничивать область действия CSS конкретным компонентом. В отличие от глобальных стилей, scoped стили гарантируют, что правила применяются только к элементам внутри компонента, не влияя на другие части приложения. В Slim.js это реализуется через встроенную поддержку <style> внутри компонента с автоматической изоляцией селекторов.

Определение scoped стилей

В Slim.js стили компонента определяются внутри метода render или в отдельном <style> блоке при использовании шаблонов. Основная идея заключается в том, что каждый компонент получает уникальный идентификатор, который автоматически добавляется к селекторам CSS. Это позволяет применять стили исключительно к элементам компонента.

Пример:

import { Component, html, css } from 'slim-js';

class MyButton extends Component {
  static styles = css`
    button {
      background-color: #4CAF50;
      color: white;
      padding: 10px 20px;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
    
    button:hover {
      background-color: #45a049;
    }
  `;

  render() {
    return html`<button>Нажми меня</button>`;
  }
}

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

В этом примере стили button применяются только к элементу внутри компонента MyButton. Если на странице есть другой элемент <button>, он останется без изменений.

Автоматическая генерация уникальных селекторов

Slim.js при компиляции компонента добавляет уникальные атрибуты к элементам и селекторам, чтобы изоляция работала корректно. Например, к тегу <button> добавляется что-то вроде data-slim-id="abc123", а CSS преобразуется:

button[data-slim-id="abc123"] { ... }

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

Вложенные селекторы и псевдоклассы

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

static styles = css`
  .card {
    border: 1px solid #ccc;
    padding: 16px;
    border-radius: 8px;
    transition: transform 0.3s;
  }

  .card:hover {
    transform: scale(1.05);
  }

  .card .title {
    font-weight: bold;
    margin-bottom: 8px;
  }

  .card .content {
    color: #666;
    font-size: 14px;
  }
`;

В этом примере .card, .card .title и .card .content будут стилизованы только внутри конкретного компонента.

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

Slim.js позволяет использовать переменные и динамические значения в scoped стилях через CSS-переменные или JS-подстановки. Это особенно удобно для темизации и изменения стилей на лету:

class ThemedButton extends Component {
  static styles = css`
    button {
      background-color: var(--btn-bg, #007BFF);
      color: var(--btn-color, #fff);
      padding: 8px 16px;
      border-radius: 4px;
      border: none;
      cursor: pointer;
    }
  `;

  render() {
    return html`<button style="--btn-bg: ${this.bgColor}; --btn-color: ${this.textColor}">Кнопка</button>`;
  }
}

Здесь значения --btn-bg и --btn-color задаются динамически через свойства компонента.

Наследование и переопределение стилей

Scoped стили в Slim.js не наследуются глобально, но можно переопределять их через каскадирование внутри компонента или через комбинирование стилей:

class PrimaryButton extends MyButton {
  static styles = css`
    button {
      background-color: #2196F3;
    }
  `;
}

PrimaryButton наследует HTML-разметку и базовые стили MyButton, но цвет кнопки переопределяется локально.

Ограничения и рекомендации

  1. Scoped стили не работают за пределами компонента. Если нужно изменить стили глобально, следует использовать глобальные CSS-файлы или переменные.
  2. Псевдоклассы :root и @keyframes применяются глобально, поэтому их необходимо тщательно именовать, чтобы избежать конфликтов.
  3. Scoped стили увеличивают количество атрибутов в DOM, что может немного повлиять на производительность при большом количестве компонентов.

Scoped стили в Slim.js обеспечивают чистую и безопасную изоляцию CSS, позволяют управлять визуальными эффектами на уровне компонентов, упрощают поддержку крупных приложений и минимизируют конфликт стилей между компонентами.