Начало работы с запросами стилей

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

Поддержка браузера

  • Хром: 105.
  • Край: 105.
  • Фаерфокс: 110.
  • Сафари: 16.

Источник

Однако спецификация включения включает в себя больше, чем просто запросы размера; он также позволяет запрашивать значения родительского стиля. Начиная с Chromium 111, вы сможете применять ограничение стиля для значений настраиваемых свойств и запрашивать у родительского элемента значение настраиваемого свойства.

Поддержка браузера

  • Хром: 111.
  • Край: 111.
  • Firefox: не поддерживается.
  • Сафари: 18.

Источник

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

Спецификация CSS Containment Module Level 3, охватывающая запросы размера и стиля, позволяет запрашивать любые стили у родительского элемента, включая пары свойств и значений, такие как font-weight: 800 . Однако при внедрении этой функции запросы стилей в настоящее время работают только со значениями пользовательских свойств CSS. Это по-прежнему очень полезно для объединения стилей и отделения данных от дизайна. Давайте посмотрим, как вы используете запросы стиля с настраиваемыми свойствами CSS:

Начало работы с запросами стиля

Допустим, у нас есть следующий HTML:

<ul class="card-list">
  <li class="card-container">
    <div class="card">
      ...
    </div>
  </li>
</ul>

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

Опрос прямых родителей

Схема запроса стиля.

В отличие от запросов к стилю, вам не нужно применять включение с использованием container-type или свойства container к .card-container , чтобы .card мог запрашивать стили своего прямого родительского элемента. Однако нам необходимо применить стили (в данном случае значения пользовательских свойств) к контейнеру (в данном случае .card-container ) или любому элементу , содержащему элемент, который мы стилизуем, в DOM. Мы не можем применять стили, которые запрашиваем, к непосредственному элементу, стилизуемому с помощью этого запроса, поскольку это может привести к бесконечным циклам.

Чтобы напрямую запросить родителя, вы можете написать:

/* styling .card based on the value of --theme on .card-container */
@container style(--theme: warm) {
  .card {
    background-color: wheat;
    border-color: brown; 
    ...
  }
}

Возможно, вы заметили, что запрос стиля обертывает запрос style() . Это необходимо для устранения неоднозначности значений размера в стилях. Например, вы можете написать запрос ширины контейнера как @container (min-width: 200px) { … } . Это будет применять стили, если ширина родительского контейнера будет не менее 200 пикселей. Однако min-width также может быть свойством CSS, и вы можете запросить значение min-width CSS, используя запросы стиля. Вот почему вы должны использовать оболочку style() , чтобы прояснить разницу: @container style(min-width: 200px) { … } .

Стилизация непрямых родителей

Если вы хотите запросить стили для любого элемента, который не является прямым родителем, вам необходимо присвоить этому элементу container-name . Например, мы можем применить стили к .card на основе стилей .card-list задав .card-list container-name и ссылаясь на него в запросе стиля.

/* styling .card based on the value of --moreGlobalVar on .card-list */
@container cards style(--moreGlobalVar: value) {
  .card {
    ...
  }
}

Обычно рекомендуется давать контейнерам имена, чтобы было понятно, что вы запрашиваете, и чтобы было проще получить доступ к этим контейнерам. Один из примеров того, где это может пригодиться, — если вы хотите напрямую стилизовать элементы внутри .card . Без именованного контейнера в .card-container они не смогут запросить его напрямую.

Но на практике все это имеет гораздо больший смысл. Давайте посмотрим на несколько примеров:

Запросы стиля в действии

Демонстрационное изображение с несколькими карточками товаров, некоторые с тегами «новые» или «низкие запасы», а также карточкой «низкий запас» на красном фоне.

Запросы к стилю особенно полезны, когда у вас есть повторно используемый компонент с несколькими вариантами или когда вы не можете контролировать все свои стили, но в определенных случаях необходимо применять изменения. В этом примере показан набор карточек продуктов, которые используют один и тот же компонент карты. На некоторых карточках товаров есть дополнительные сведения/примечания, такие как «Новый» или «Низкий запас», которые активируются настраиваемым свойством с именем --detail . Кроме того, если товар находится в состоянии «Низкий запас», он получает темно-красную рамку. Этот тип информации, скорее всего, отображается на сервере и может быть применен к карточкам с помощью встроенных стилей, например:

 <div class="product-list">
  <div class="product-card-container" style="--detail: new">
    <div class="product-card">
      <div class="media">
        <img .../>
      <div class="comment-block"></div>
    </div>
  </div>
  <div class="meta">
    ...
  </div>
  </div>
  <div class="product-card-container" style="--detail: low-stock">
    ...
  </div>
  <div class="product-card-container">
    ...
  </div>
  ...
</div>

Учитывая эти структурированные данные, вы можете передавать значения в --detail и использовать это пользовательское свойство CSS для применения стилей:

@container style(--detail: new) {
  .comment-block {
    display: block;
  }
  
  .comment-block::after {
    content: 'New';
    border: 1px solid currentColor;
    background: white;
    ...
  }
}

@container style(--detail: low-stock) {
  .comment-block {
    display: block;
  }
  
  .comment-block::after {
    content: 'Low Stock';
    border: 1px solid currentColor;
    background: white;
    ...
  }
  
  .media-img {
    border: 2px solid brickred;
  }
}

Приведенный выше код позволяет нам применить чип для --detail: low-stock и --detail: new , но вы, возможно, заметили некоторую избыточность в блоке кода. В настоящее время нет способа запросить наличие --detail с помощью @container style(--detail) , что позволило бы лучше совместно использовать стили и уменьшить повторение. Эта возможность в настоящее время обсуждается в рабочей группе.

Карты погоды

В предыдущем примере для применения стилей использовалось одно настраиваемое свойство с несколькими возможными значениями. Но вы можете смешать это, используя и запрашивая несколько пользовательских свойств. Возьмем этот пример карты погоды:

Демо-карты погоды.

Чтобы оформить градиенты фона и значки для этих карточек, обратите внимание на характеристики погоды, например «облачно», «дождливо» или «солнечно»:

@container style(--sunny: true) {
  .weather-card {
    background: linear-gradient(-30deg, yellow, orange);
  }
  
  .weather-card:after {
    content: url(<data-uri-for-demo-brevity>);
    background: gold;
  }
}

Таким образом, вы можете стилизовать каждую карту с учетом ее уникальных характеристик. Но вы также можете стилизовать комбинации характеристик (пользовательских свойств), используя комбинатор and так же, как и для медиа-запросов . Например, день, который одновременно пасмурный и солнечный, будет выглядеть так:

@container style(--sunny: true) and style(--cloudy: true) {
    .weather-card {
      background: linear-gradient(24deg, pink, violet);
    }
  
  .weather-card:after {
      content: url(<data-uri-for-demo-brevity>);
      background: violet;
  }
}

Отделение данных от дизайна

В обеих этих демонстрациях структурное преимущество заключается в отделении уровня данных (DOM, который будет отображаться на странице) от примененных стилей. Стили записываются как возможные варианты, которые живут в стиле компонентов, а конечная точка может отправлять данные, которые затем будут использовать для стилизации компонента. Вы можете использовать одно значение, например, в первом случае, обновляя значение --detail , или несколько переменных, например, во втором случае (устанавливая --rainy или --cloudy или --sunny . И самое приятное) заключается в том, что вы также можете комбинировать эти значения: проверка --sunny и --cloudy может отобразить стиль частичной облачности.

Обновление значений пользовательских свойств с помощью JavaScript можно легко выполнить либо при настройке модели DOM (т. е. при создании компонента в платформе), либо обновить в любое время с помощью <parentElem>.style.setProperty('--myProperty', <value>) . я

Вот демонстрация, которая в нескольких строках кода обновляет --theme кнопки и применяет стили, используя запросы стилей и это настраиваемое свойство ( --theme ):

Оформите карту с помощью запросов стиля. Для обновления значений пользовательских свойств используется следующий код JavaScript:

const themePicker = document.querySelector('#theme-picker')
const btnParent = document.querySelector('.btn-section');

themePicker.addEventListener('input', (e) => {
  btnParent.style.setProperty('--theme', e.target.value);
})

Функции, подробно описанные в этой статье, — это только начало. Вы можете ожидать большего от контейнерных запросов, которые помогут вам создавать динамические, отзывчивые интерфейсы. Что касается конкретно запросов стиля, то здесь все еще остается несколько открытых вопросов. Одним из них является реализация запросов стилей для стилей CSS помимо пользовательских свойств. Это уже часть текущего уровня спецификации, но еще не реализовано ни в одном браузере. Ожидается, что оценка логического контекста будет добавлена ​​к текущему уровню спецификации, когда нерешенная проблема будет решена, а запрос диапазона запланирован на следующий уровень спецификации.