CSS псевдокласс :scope
CSS псевдокласс :scope представляет элементы области видимости. Читайте о псевдоклассе и практикуйтесь с примерами.
CSS псевдокласс :scope соответствует элементу, относительно которого разрешается селектор — его опорному элементу. В обычных DOM-запросах опорным элементом является тот элемент, на котором вызывается метод запроса; внутри Shadow DOM — это корень теневого дерева.
На этой странице объясняется, что означает «область видимости» для селектора, почему :scope является преимущественно инструментом JavaScript, а не таблиц стилей, два основных места, где он меняет поведение, и подводные камни, которых стоит остерегаться.
Что такое опорный элемент
Каждый селектор сопоставляется относительно некоего элемента. Когда вы пишете CSS в таблице стилей, опорным элементом является корень документа, поэтому :scope там эквивалентен :root и сам по себе редко полезен.
:scope становится значимым, когда опорный элемент — не корень, что особенно важно при запросах к DOM из JavaScript:
element.querySelector(selector)иelement.querySelectorAll(selector)разрешают селектор относительноelement. Здесь:scopeуказывает на самelement.- Методы запросов у
ShadowRootиспользуют корень теневого дерева как опорный элемент.
Без :scope селектор, переданный в element.querySelector(), по-прежнему сопоставляется с целым поддеревом, а не привязывается к element. Это удивляет многих разработчиков — см. подводный камень ниже.
Зачем использовать
Основная причина обращаться к :scope — привязать селектор к элементу, по которому выполняется запрос, чтобы можно было выбирать непосредственных потомков или иным образом выразить «относительно этого места»:
// Match only sections that are direct children of container.
container.querySelectorAll(':scope > section');:scope значим внутри перечисленных выше методов запросов (querySelector, querySelectorAll и живой проверки Element.matches()). Он не оказывает особого эффекта в closest() или в обычных правилах таблиц стилей.
Примечание: старый атрибут <style scoped>, который когда-то позволял блоку <style> применяться только внутри родительского элемента, был удалён из браузеров. Сегодня изоляция стилей реализуется с помощью Shadow DOM (или инструментов сборки), а :scope остаётся помощником для DOM-запросов.
Версия
Синтаксис
В таблице стилей синтаксис такой же, как у любого другого псевдокласса:
:scope {
/* declarations — equivalent to :root in a normal stylesheet */
}В JavaScript он передаётся внутри строки селектора:
element.querySelectorAll(':scope > .child');Пример: привязка запроса к элементу
В примере ниже container.querySelector(':scope > section') выбирает только тот <section>, который является непосредственным потомком .container. Найденный раздел перекрашивается для подтверждения того, что запрос сработал.
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
.container {
margin: 40px auto;
max-width: 700px;
background-color: #eeeeee;
padding: 20px;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.25);
}
section {
padding: 30px;
}
</style>
</head>
<body>
<h2>:scope selector example</h2>
<div class="container">
<section>
<p>
Inside the scope.
</p>
</section>
</div>
<script>
const container = document.querySelector('.container');
const scopeElement = container.querySelector(':scope > section');
scopeElement.style.backgroundColor = '#1c87c9';
scopeElement.style.color = '#fff';
</script>
</body>
</html>Частая ошибка: выбор непосредственных потомков
Самая распространённая причина использовать :scope — выбор непосредственных потомков элемента, по которому выполняется запрос. Комбинатор вроде > .x не может стоять самостоятельно — element.querySelector('> .x') выбрасывает SyntaxError. Ему нужна левая часть, и :scope её предоставляет:
<ul id="list">
<li>A</li>
<li>
<ul>
<li>B (nested)</li>
</ul>
</li>
</ul>const list = document.getElementById('list');
// SyntaxError — "> li" is not a complete selector:
// list.querySelectorAll('> li');
// Correct: only the direct <li> children of #list (A and the one wrapping the nested list),
// NOT "B (nested)".
list.querySelectorAll(':scope > li');Без :scope вызов list.querySelectorAll('li') вернул бы и вложенный элемент B, поскольку простой селектор потомков охватывает всё поддерево. :scope > — это идиоматический способ сказать «непосредственные потомки элемента, по которому выполняется запрос».
Поддержка браузерами
:scope поддерживается во всех современных браузерах для методов DOM-запросов. В обычной таблице стилей он не оказывает никакого эффекта сверх поведения :root.
Связанные главы
- CSS Selectors — полный справочник по селекторам.
- CSS Selector — основы синтаксиса селекторов.