CSS Container Queries

CSS Container Queries позволяют создавать компоненты, дизайн которых адаптируется не только к размерам окна браузера, но и к размеру родительского контейнера. Это особенно полезно в компонентных фреймворках, таких как Lit, где повторно используемые элементы могут находиться в различных контекстах. В отличие от медиа-запросов, которые ориентируются на размеры viewport, контейнерные запросы реагируют на размеры самого контейнера, делая компоненты более гибкими.


Подключение и использование контейнерных запросов

В Lit стили компонентов обычно задаются через шаблонную строку css в static styles. Для работы с container queries необходимо определить контейнер и использовать директиву @container. Например:

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

class ResponsiveCard extends LitElement {
  static styles = css`
    :host {
      display: block;
      container-type: inline-size;
    }

    .card {
      padding: 16px;
      background-color: #f5f5f5;
      border-radius: 8px;
    }

    @container (min-width: 400px) {
      .card {
        background-color: #e0f7fa;
        padding: 24px;
      }
    }

    @container (min-width: 600px) {
      .card {
        background-color: #b2ebf2;
        padding: 32px;
      }
    }
  `;

  render() {
    return html`<div class="card">Контент карточки</div>`;
  }
}

customElements.define('responsive-card', ResponsiveCard);

Разбор примера:

  • :host объявляется как контейнер с container-type: inline-size, что позволяет использовать контейнерные запросы на основе ширины.
  • @container задает стили, которые применяются при достижении определённой ширины контейнера.
  • Такой подход позволяет компоненту менять стиль в зависимости от того, где он находится, не зависимо от размера всего окна браузера.

Container-Type и Container-Name

Контейнеры могут быть разных типов:

  • size — отслеживает как ширину, так и высоту контейнера.
  • inline-size — отслеживает только ширину.
  • block-size — отслеживает только высоту.

Можно также задать имя контейнера с помощью container-name, что позволяет направлять стили только на определённые контейнеры:

:host {
  container-type: size;
  container-name: card-container;
}

@container card-container (min-width: 500px) {
  .card {
    font-size: 1.5rem;
  }
}

Интеграция с динамическими стилями Lit

Lit поддерживает динамические свойства через CSSResult и styleMap, что позволяет комбинировать container queries с реактивными данными:

import { LitElement, html, css } from 'lit';
import { styleMap } from 'lit/directives/style-map.js';

class DynamicCard extends LitElement {
  static styles = css`
    :host {
      display: block;
      container-type: inline-size;
    }

    .card {
      padding: 16px;
      border-radius: 8px;
      transition: all 0.3s ease;
    }

    @container (min-width: 400px) {
      .card {
        padding: 24px;
      }
    }

    @container (min-width: 600px) {
      .card {
        padding: 32px;
      }
    }
  `;

  static properties = {
    color: { type: String }
  };

  render() {
    const styles = { backgroundColor: this.color || '#f5f5f5' };
    return html`<div class="card" style=${styleMap(styles)}>Контент карточки</div>`;
  }
}

customElements.define('dynamic-card', DynamicCard);

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


Взаимодействие с Shadow DOM

Использование container queries в Lit особенно эффективно в Shadow DOM, так как все стили инкапсулированы. Это позволяет компонентам изменять оформление в зависимости от контейнера, в котором они встроены, без риска конфликтов с внешними стилями. Важно помнить:

  • Контейнерные запросы работают только на контейнеры, объявленные в том же shadow root или в родительских элементах, имеющих container-type.
  • Для сложных компонентов можно использовать вложенные container queries, задавая контейнеры на разных уровнях DOM.

Практические рекомендации

  • Всегда задавать container-type у :host, чтобы компонент корректно реагировал на изменения размера контейнера.
  • Использовать именованные контейнеры, если один компонент может находиться в разных контекстах.
  • Совмещать container queries с динамическими стилями Lit для максимальной реактивности.
  • Не полагаться на container queries вместо медиа-запросов для глобальных адаптивных изменений; они предназначены для локальной адаптивности компонентов.

Контейнерные запросы открывают новые возможности для создания автономных и адаптивных веб-компонентов в Lit, позволяя компонентым гибко реагировать на изменение окружающего пространства без вмешательства в глобальные стили.