@scope
Ограниченная доступность
Эта функция не является базовой, так как она не работает в некоторых из самых широко используемых браузеров.
Правило @scope CSS правило позволяет выбирать элементы в определённых поддеревьях DOM, точно нацеливаясь на элементы без написания чрезмерно специфичных селекторов, которые сложно переопределить, и без чрезмерной связи селекторов со структурой DOM.
В JavaScript, @scope можно получить через интерфейс модели CSS-объекта CSSScopeRule.
Синтаксис
Правило @scope содержит один или несколько наборов правил (называемых **правилами стилей области видимости**) и определяет область, в которой они применяются к выбранным элементам. @scope можно использовать двумя способами:
-
Как самостоятельный блок внутри вашего CSS, в котором он включает раздел преамбулы, включающий **корень области видимости** и необязательные селекторы **границы области видимости** — они определяют верхние и нижние границы области видимости.
@scope (scope root) to (scope limit) { rulesets } -
Как встроенные стили, включенные внутри элемента
<style>в вашем HTML, в этом случае преамбула опускается, а включённый набор правил автоматически настраивается на родительский элемент элемента<style>.<parent-element> <style> @scope { rulesets } </style> </parent-element>
Описание
Сложный веб-документ может включать компоненты, такие как заголовки, подвалы, новостные статьи, карты, медиаплееры, рекламные объявления и другие. По мере увеличения сложности эффективное управление стилями для этих компонентов становится более важным, и эффективное ограничение области видимости стилей помогает нам справиться с этой сложностью. Рассмотрим следующее дерево DOM:
body
└─ article.feature
├─ section.article-hero
│ ├─ h2
│ └─ img
│
├─ section.article-body
│ ├─ h3
│ ├─ p
│ ├─ img
│ ├─ p
│ └─ figure
│ ├─ img
│ └─ figcaption
│
└─ footer
├─ p
└─ img
Если вы хотите выбрать элемент <img> внутри элемента <section> с классом article-body, вы можете сделать следующее:
- Написать селектор, например,
.feature > .article-body > img. Однако, он имеет высокую специфичность, поэтому его сложно переопределить, а также сильно связан со структурой DOM. Если структура вашего разметки изменится в будущем, вам, возможно, придётся переписывать ваш CSS. - Написать что-то менее специфичное, например,
.article-body img. Однако, это выберет все изображения внутриsection.
Здесь пригодится @scope. Она позволяет определить точную область, в пределах которой ваши селекторы могут нацеливаться на элементы. Например, вы можете решить вышеупомянутую проблему, используя автономный блок @scope следующим образом:
@scope (.article-body) to (figure) {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
Селектор корня области видимости .article-body определяет верхнюю границу дерева DOM, в котором будет применяться набор правил, а селектор границы области видимости figure определяет нижнюю границу. В результате, будут выбраны только элементы <img> внутри <section> с классом article-body, но не внутри элементов <figure>.
Примечание: Этот вид ограничения области видимости — с верхней и нижней границей — обычно называют **объёмной областью видимости**.
Если вы хотите выбрать все изображения внутри <section> с классом article-body, вы можете опустить ограничение области видимости:
@scope (.article-body) {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
Или вы можете включить свой блок @scope в виде встроенных стилей внутри элемента <style>, который, в свою очередь, находится внутри <section> с классом article-body:
<section class="article-body">
<style>
@scope {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
</style>
<!-- ... -->
</section>
Примечание: Важно понимать, что, хотя @scope позволяет изолировать применение селекторов к определённым поддеревьям DOM, она не полностью изолирует применённые стили внутри этих поддеревьев. Это наиболее заметно при наследовании — свойства, которые наследуются потомками (например, color или font-family) всё ещё будут наследовать, за пределами любого установленного ограничения области видимости.
Псевдокласс :scope
В контексте блока @scope псевдокласс :scope представляет корень области видимости — он предоставляет простой способ применения стилей к самому корню области видимости изнутри области видимости:
@scope (.feature) {
:scope {
background: rebeccapurple;
color: antiquewhite;
font-family: sans-serif;
}
}
Фактически, :scope неявно предваряет все правила стилей области видимости. Если вы хотите, вы можете явно предварять :scope или предварять селектор вложенности (&) для достижения того же эффекта, если вы считаете эти представления более понятными.
Три правила в следующем блоке эквивалентны по тому, что они выбирают:
@scope (.feature) {
img { ... }
:scope img { ... }
& img { ... }
}
Примечания по использованию селекторов области видимости
-
Граница области видимости может использовать
:scopeдля указания конкретного требования к отношению между границей области видимости и корнем. Например:/* figure is only a limit when it is a direct child of the :scope */ @scope (.article-body) to (:scope > figure) { ... } -
Граница области видимости может ссылаться на элементы за пределами корня области видимости, используя
:scope. Например:/* figure is only a limit when the :scope is inside .feature */ @scope (.article-body) to (.feature :scope figure) { ... } -
Правила стилей области видимости не могут выйти за пределы поддерева. Выборки, такие как
:scope + pявляются недопустимыми, потому что этот выбор был бы за пределами поддерева. -
Совершенно допустимо определить корень области видимости и ограничение как список селекторов, в этом случае будут определены несколько областей видимости. В следующем примере стили применяются к любому
<img>внутри<section>с классомarticle-heroилиarticle-body, но не если он вложен в<figure>:@scope (.article-hero, .article-body) to (figure) { img { border: 5px solid black; background-color: goldenrod; } }
Специфичность в @scope
Включение набора правил внутри блока @scope не влияет на специфичность его селектора, независимо от селекторов, используемых внутри корня и ограничения области видимости. Например:
@scope (.article-body) {
/* img has a specificity of 0-0-1, as expected */
img { ... }
}
Однако, если вы решите явно предварять псевдокласс :scope к вашим селекторам области видимости, вам нужно будет учитывать это при расчёте их специфичности. :scope, как и все обычные псевдоклассы, имеет специфичность 0-1-0. Например:
@scope (.article-body) {
/* :scope img has a specificity of 0-1-0 + 0-0-1 = 0-1-1 */
:scope img { ... }
}
При использовании селектора & внутри блока @scope & представляет собой селектор корня области видимости; он вычисляется как селектор, заключённый внутри функции псевдокласса :is(). Итак, например, в:
@scope (figure, #primary) {
& img { ... }
}
& img эквивалентно :is(figure, #primary) img. Поскольку :is() использует специфичность самого специфичного аргумента (#primary, в данном случае), специфичность селектора области видимости & img поэтому составляет 1-0-0 + 0-0-1 = 1-0-1.
Разница между :scope и & внутри @scope
:scope представляет сопоставленный корень области видимости, а & представляет селектор, используемый для сопоставления корня области видимости. Благодаря этому, можно объединять & несколько раз. Однако, :scope можно использовать только один раз — вы не можете сопоставить корень области видимости внутри корня области видимости.
@scope (.feature) {
/* Selects a .feature inside the matched root .feature */
& & { ... }
/* Doesn't work */
:scope :scope { ... }
}
Как разрешаются конфликты @scope
@scope добавляет новый критерий к каскаду CSS: близость области видимости. Это означает, что при конфликте стилей в двух областях видимости применяется стиль, у которого наименьшее количество переходов вверх по иерархии дерева DOM к корню области видимости. Посмотрим на пример, чтобы понять, что это значит.
Рассмотрим следующий фрагмент HTML, где разные тематические карточки вложены друг в друга:
<div class="light-theme">
<p>Light theme text</p>
<div class="dark-theme">
<p>Dark theme text</p>
<div class="light-theme">
<p>Light theme text</p>
</div>
</div>
</div>
Если вы написали CSS для темы так, то столкнетесь с проблемами:
.light-theme {
background: #ccc;
}
.dark-theme {
background: #333;
}
.light-theme p {
color: black;
}
.dark-theme p {
color: white;
}
Ожидается, что абзац внутри будет окрашен в черный цвет, так как он находится внутри карточки со светлой темой. Однако, на него влияют как .light-theme p, так и .dark-theme p. Поскольку правило .dark-theme p появляется позже в порядке следования, оно применяется, и абзац оказывается неверно окрашенным в белый цвет.
Для исправления этой проблемы можно использовать @scope следующим образом:
@scope (.light-theme) {
:scope {
background: #ccc;
}
p {
color: black;
}
}
@scope (.dark-theme) {
:scope {
background: #333;
}
p {
color: white;
}
}
Теперь внутренний абзац правильно окрашен в черный цвет. Это происходит потому, что он находится всего в одном уровне иерархии дерева DOM от корня области видимости .light-theme, но в двух уровнях от корня области видимости .dark-theme. Поэтому стиль со светлой темой побеждает.
Примечание: Близость области видимости имеет приоритет над порядком следования, но сама уступает другим критериям с более высоким приоритетом, таким как важность, слои и уникальность.
Формальный синтаксис
@scope =
@scope [ ( <scope-start> ) ]? [ to ( <scope-end> ) ]? { <block-contents> }
Примеры
Базовый стиль внутри корней области видимости
В этом примере мы используем два отдельных @scope блока для соответствия ссылкам внутри элементов с классами .light-scheme и .dark-scheme соответственно. Обратите внимание, как :scope используется для выбора и предоставления стилей самим корням областей видимости. В этом примере корнями областей видимости являются элементы <div> с примененными классами.
HTML
<div class="light-scheme">
<p>
MDN contains lots of information about
<a href="/en-US/docs/Web/HTML">HTML</a>,
<a href="/en-US/docs/Web/CSS">CSS</a>, and
<a href="/en-US/docs/Web/JavaScript">JavaScript</a>.
</p>
</div>
<div class="dark-scheme">
<p>
MDN contains lots of information about
<a href="/en-US/docs/Web/HTML">HTML</a>,
<a href="/en-US/docs/Web/CSS">CSS</a>, and
<a href="/en-US/docs/Web/JavaScript">JavaScript</a>.
</p>
</div>
CSS
@scope (.light-scheme) {
:scope {
background-color: plum;
}
a {
color: darkmagenta;
}
}
@scope (.dark-scheme) {
:scope {
background-color: darkmagenta;
color: antiquewhite;
}
a {
color: plum;
}
}
Результат
Вышеприведенный код отображается так:
Корни областей видимости и ограничения областей видимости
В этом примере есть фрагмент HTML, соответствующий структуре DOM, о которой мы говорили ранее в разделе Описание. Эта структура представляет собой типичное резюме статьи. Важно отметить элементы <img>, которые вложены на разных уровнях в структуре.
Цель этого примера — показать, как использовать корень области видимости и ограничение, чтобы стилизовать элементы <img> начиная с вершины иерархии, но только до (не включая) <img> внутри элемента <figure> — фактически создавая область видимости в виде кольца.
HTML
<article class="feature">
<section class="article-hero">
<h2>Article heading</h2>
<img alt="image" />
</section>
<section class="article-body">
<h3>Article subheading</h3>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam euismod
consectetur leo, nec eleifend quam volutpat vitae. Duis quis felis at
augue imperdiet aliquam. Morbi at felis et massa mattis lacinia. Cras
pharetra velit nisi, ac efficitur magna luctus nec.
</p>
<img alt="image" />
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<figure>
<img alt="image" />
<figcaption>My infographic</figcaption>
</figure>
</section>
<footer>
<p>Written by Chris Mills.</p>
<img alt="image" />
</footer>
</article>
CSS
В нашем CSS есть два @scope блока:
- Первый
@scopeблок определяет корень своей области видимости как элементы с классом.feature(в данном случае, только внешний<div>), демонстрируя, как@scopeможно использовать для оформления определенного подмножества HTML. - Второй
@scopeблок также определяет корень своей области видимости как элементы с классом.feature, но дополнительно определяет ограничение области видимостиfigure. Это гарантирует, что правила внутри будут применяться только к соответствующим элементам внутри корня области видимости (<div class="figure"> ... </div>в данном случае), которые не находятся внутри потомков элементов<figure>. Этот@scopeблок содержит единственное правило, которое стилизует элементы<img>толстой черной границей и золотистым фоном.
/* Scoped CSS */
@scope (.feature) {
:scope {
background: rebeccapurple;
color: antiquewhite;
font-family: sans-serif;
}
figure {
background-color: white;
border: 2px solid black;
color: black;
padding: 10px;
}
}
/* Donut scope */
@scope (.feature) to (figure) {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
Результат
В отрисованном коде обратите внимание, как все элементы <img> стилизованы толстой границей и золотым фоном, кроме одного внутри элемента <figure> (обозначенного как "Моя инфографика").
Спецификации
Совместимость с браузерами
| Рабочие столы | Мобильные устройства | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox для Android | Opera Android | Safari на IOS | Samsung Internet | WebView Android | |
@scope |
118 | 118 | 128 | 104 | 17.4 | 118 | Нет | 79 | 17.4 | 25.0 | 118 |
См. также
:scopeCSSScopeRule-
Ограничьте область действия ваших селекторов с помощью правила CSS
@scopeна developer.chrome.com (2023)
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/CSS/@scope