Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Область стилей: @scope

Селектор h3 найдёт все заголовки страницы. Чтобы стиль действовал только внутри карточки, обычно пишут .card h3 или дают заголовку свой класс по БЭМ. Правило @scope предлагает третий путь: оно задаёт область — часть страницы, внутри которой работают правила.

Первая область

В скобках после @scope указывают корень области — элемент, внутри которого действуют стили. Правила внутри фигурных скобок применяются только к его потомкам:

<style>
  @scope (.card) {
    h3 { margin: 0; color: rebeccapurple; }
  }
</style>
 
<div class="card">
  <h3>Анна — внутри карточки</h3>
</div>
<h3>Заголовок снаружи</h3>

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

Псевдокласс :scope

Чтобы оформить сам корень области, используют :scope:

<style>
  @scope (.card) {
    :scope { padding: 12px; border-radius: 8px; background: lavender; }
    h3 { margin: 0 0 4px; }
    p { margin: 0; color: dimgray; }
  }
</style>
 
<div class="card">
  <h3>Анна</h3>
  <p>Фронтенд-разработчица</p>
</div>

Все стили компонента собраны в одном блоке, и у вложенных элементов нет ни одного класса.

Нижняя граница: to

После to указывают, где область заканчивается. Стили не заходят внутрь этого элемента. Получается область «с дыркой» — её называют бубликом. Так оформляют обёртку карточки, но не трогают текст, который в неё вставили:

<style>
  @scope (.card) to (.content) {
    p { margin: 0; font-size: 13px; color: gray; }
  }
  .card { padding: 12px; background: whitesmoke; }
</style>
 
<div class="card">
  <p>Подпись карточки — серая и мелкая</p>
  <div class="content">
    <p>Текст статьи внутри .content остался обычным.</p>
  </div>
</div>

Ближайший корень побеждает

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

<style>
  .dark { padding: 12px; background: #333; color: white; }
  .light { padding: 12px; margin-top: 8px; background: white; color: black; }
  @scope (.light) { a { color: darkblue; } }
  @scope (.dark) { a { color: gold; } }
</style>
 
<div class="dark">
  <a href="#">Ссылка в тёмной теме</a>
  <div class="light">
    <a href="#">Ссылка в светлой теме внутри тёмной</a>
  </div>
</div>

Правило для .dark идёт последним, но нижняя ссылка тёмно-синяя: корень .light к ней ближе. С обычными селекторами .light a и .dark a победило бы правило, записанное ниже.

@scope, БЭМ и вложенность

СпособКак ограничивает стилиСпецифичность
БЭМуникальные имена классов у каждого элементаодин класс
Вложенностьселектор родителя перед селектором потомкарастёт с каждым уровнем
@scopeобласть с корнем и нижней границейкорень не добавляет веса

БЭМ из главы об архитектуре работает везде и остаётся надёжным выбором. @scope полезен, когда разметку нельзя обвесить классами — например, для текста из редактора статей.

Поддержка

@scope работает в Chrome и Edge с 2023 года и в Safari с 2024 года. Состояние поддержки в Firefox смотрите на caniuse.com. Браузер без поддержки пропустит весь блок, поэтому важные стили на одном @scope пока не держите.

Частая ошибка

Считать, что @scope изолирует компонент от остальных стилей. Он лишь ограничивает свои правила, а общие стили страницы по-прежнему действуют внутри:

<style>
  p { color: crimson; }
  @scope (.card) {
    h3 { color: seagreen; }
  }
</style>
 
<div class="card">
  <h3>Заголовок карточки</h3>
  <p>Абзац всё равно красный — правило p действует везде.</p>
</div>

Полную изоляцию дают только веб-компоненты с теневым DOM, а @scope — это способ направить свои стили, а не заслониться от чужих.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.