Адаптивная верстка в компонентах

Компоненты в Lit строятся на основе стандартного Web Components API, расширяя его удобными инструментами для реактивного обновления и шаблонной разметки. Основой является класс, наследующийся от LitElement, который предоставляет возможность описывать состояние компонента через свойства и шаблоны через функцию render().

import { LitElement, html, css } from 'lit';

class MyComponent extends LitElement {
  static properties = {
    title: { type: String }
  };

  static styles = css`
    :host {
      display: block;
      padding: 16px;
      box-sizing: border-box;
    }
  `;

  render() {
    return html`<h1>${this.title}</h1>`;
  }
}

customElements.define('my-component', MyComponent);

Ключевой момент — использование :host в стилях для управления корневым элементом компонента. Это важно для адаптивной верстки, чтобы компоненты корректно реагировали на изменения размеров контейнера.


Гибкая сетка внутри компонентов

Для адаптивности критически важно использовать flexbox и CSS Grid. В Lit стили можно определять как глобально для компонента, так и локально.

static styles = css`
  :host {
    display: block;
    padding: 1rem;
  }
  .grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
  }
  .item {
    background: lightgray;
    padding: 16px;
    border-radius: 8px;
  }
`;

Использование repeat(auto-fit, minmax()) позволяет сетке автоматически подстраиваться под ширину контейнера, создавая адаптивные колонки без медиа-запросов.


Медиа-запросы внутри компонентов

Lit поддерживает стандартный CSS, поэтому можно применять медиа-запросы для тонкой настройки внешнего вида на разных устройствах:

static styles = css`
  :host {
    display: block;
  }

  .container {
    display: flex;
    flex-direction: row;
  }

  @media (max-width: 768px) {
    .container {
      flex-direction: column;
    }
  }
`;

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


Реактивные свойства и адаптивное состояние

С помощью реактивных свойств можно изменять внутреннее состояние компонента в зависимости от размеров окна или контейнера. Комбинация ResizeObserver и реактивных свойств позволяет динамически адаптировать разметку:

class ResponsiveComponent extends LitElement {
  static properties = {
    smallScreen: { type: Boolean }
  };

  constructor() {
    super();
    this.smallScreen = false;
    this._resizeObserver = new ResizeObserver(entries => {
      for (let entry of entries) {
        this.smallScreen = entry.contentRect.width < 600;
      }
    });
  }

  connectedCallback() {
    super.connectedCallback();
    this._resizeObserver.observe(this);
  }

  disconnectedCallback() {
    this._resizeObserver.disconnect();
    super.disconnectedCallback();
  }

  render() {
    return html`
      <div class="${this.smallScreen ? 'vertical' : 'horizontal'}">
        <slot></slot>
      </div>
    `;
  }
}

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


Адаптивные шрифты и размеры

Для текста и элементов интерфейса удобно использовать единицы rem и vw вместо фиксированных px. Это обеспечивает масштабирование компонентов в зависимости от размера контейнера и экрана:

static styles = css`
  h1 {
    font-size: 2rem;
  }
  p {
    font-size: 1rem;
  }

  @media (max-width: 600px) {
    h1 {
      font-size: 5vw;
    }
    p {
      font-size: 3vw;
    }
  }
`;

Использование vw в сочетании с rem позволяет сохранять читаемость текста на любых устройствах.


Инкапсуляция стилей и модификаторы

Локальные стили компонентов защищают их от глобальных конфликтов. Для изменения внешнего вида компонента на разных экранах можно использовать CSS-переменные:

static styles = css`
  :host {
    --padding: 16px;
    display: block;
    padding: var(--padding);
  }

  @media (max-width: 768px) {
    :host {
      --padding: 8px;
    }
  }
`;

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


Динамическое управление классами и стилями

Lit позволяет управлять классами через выражения внутри шаблона. Это упрощает создание адаптивных интерфейсов без дублирования CSS:

render() {
  const classes = {
    horizontal: !this.smallScreen,
    vertical: this.smallScreen
  };
  return html`<div class="${Object.keys(classes).filter(k => classes[k]).join(' ')}">
    <slot></slot>
  </div>`;
}

Такой подход уменьшает зависимость от медиа-запросов, позволяя изменять стили в зависимости от состояния компонента.


Интеграция с внешними библиотеками

Для сложных интерфейсов можно использовать сторонние CSS-фреймворки (например, Tailwind или Bootstrap) внутри Lit-компонентов. Важно обернуть сторонние классы внутри локальных контейнеров, чтобы сохранить инкапсуляцию стилей:

render() {
  return html`
    <div class="wrapper">
      <button class="btn btn-primary">Кнопка</button>
    </div>
  `;
}

Стили будут применяться только внутри wrapper, не затрагивая другие элементы страницы.


Вывод

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