Область стилей: @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 — это способ направить свои стили, а не заслониться от чужих.