Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions css/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ groups:
- lang
- root
- indeterminate
- pseudo-class-scope
- picture-in-picture
- fullscreen
- name: 'Псевдоэлементы'
Expand Down
100 changes: 100 additions & 0 deletions css/pseudo-class-scope/demos/basic/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<title>:scope — Псевдокласс — Дока</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500&display=swap">
<style>
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html { color-scheme: dark; }
body {
min-height: 100vh; padding: 50px; display: flex; align-items: center; justify-content: center;
background-color: #18191C; color: #FFFFFF; font-family: "Roboto", sans-serif; font-size: 16px;
}
@media (max-width: 768px) { body { padding: 30px; } }

.container { width: 100%; max-width: 840px; display: grid; gap: 20px; }
.row { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
@media (max-width: 768px) { .row { grid-template-columns: 1fr; } }
.card { background: #222328; border: 1px solid #34353B; border-radius: 10px; padding: 18px; }
h1 { margin-bottom: 17px; font-weight: 500; font-size: 1.625rem; }
h2 { margin-top: 40px; margin-bottom: 17px; font-weight: 500; font-size: 1.375rem; }
p { margin: 7px 0; font-size: 1rem; line-height: 1.4; }

code { font-family: "Roboto Mono", monospace; font-size: calc(1em - 1px); }

@scope (.scoped) {
:scope { outline: 2px dashed #2E9AFF; outline-offset: 6px; }
:scope > h2 { color: #2E9AFF; }
:scope > ul > li { color: #B8D9FF; }
}

.highlight { background: rgba(46,154,255,0.15); border-radius: 6px; }
.controls { display: flex; gap: 8px; }
.button { min-width: 210px; border: 2px solid transparent; border-radius: 6px; padding: 9px 15px; color: #000; font-size: 18px; font-weight: 300; font-family: inherit; transition: background-color 0.2s linear; cursor: pointer; }
.button-blue { background: #2E9AFF; }
.button:hover { background: #FFFFFF; }
.button:focus-visible { border: 2px solid #FFFFFF; outline: none; }
.button:focus { border: 2px solid #FFFFFF; outline: none; }

ul, ol { padding-left: 20px; }
li { margin: 6px 0; }
</style>
</head>
<body>
<div class="container">
<div class="row">
<section class="card scoped">
<h2>CSS: область с @scope</h2>
<p>Внутри <code>@scope (.scoped)</code> псевдокласс <code>:scope</code> совпадает с этим блоком.</p>
<ul>
<li>Этот пункт стилизован через <code>:scope &gt; ul &gt; li</code></li>
<li>И этот тоже</li>
<li>А заголовок окрашен через <code>:scope &gt; h2</code></li>
</ul>
</section>

<section class="card">
<h2>JS: поиск относительно <code>:scope</code></h2>
<p>Кнопка подсветит только непосредственных детей списка в правом блоке.</p>
<div class="controls">
<button class="button button-blue" id="highlight">Подсветить детей</button>
<button class="button" id="clear">Сбросить</button>
</div>
<ul id="js-list" style="margin-top: 12px;">
<li>Я — ребёнок</li>
<li>Я тоже — ребёнок
<ul>
<li>А я — внук</li>
</ul>
</li>
<li>И я — ребёнок</li>
</ul>
</section>
</div>
</div>

<script>
const list = document.getElementById('js-list')
const btn = document.getElementById('highlight')
const clear = document.getElementById('clear')

function highlightDirectChildren() {
const items = list.querySelectorAll(':scope > li')
items.forEach((li) => li.classList.add('highlight'))
}
function clearHighlights() {
list.querySelectorAll('.highlight').forEach((li) => li.classList.remove('highlight'))
}

btn.addEventListener('click', highlightDirectChildren)
clear.addEventListener('click', clearHighlights)
</script>
</body>
</html>


77 changes: 77 additions & 0 deletions css/pseudo-class-scope/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
title: "`:scope`"
description: "Позволяет ссылаться на текущий элемент‑корень в сложных селекторах: в JS‑поиске через querySelector* и внутри CSS‑области @scope."
baseline:
- group: scope-pseudo
features:
- css.selectors.scope
authors:
- drakesbot12
keywords:
- scope
- область видимости селекторов
- querySelector
- subject selector
related:
- js/query-selector
- css/has
- css/list-style
tags:
- doka
---

## Кратко

`:scope` — псевдокласс, который соответствует «текущему корню» селектора.

- В JavaScript, при вызове `element.querySelector(All)`, `:scope` указывает на сам `element`. Это позволяет удобно писать селекторы с комбинаторами (`>`, `+`, `~`) относительно элемента, с которого начат поиск.
- В CSS, внутри [`@scope`](/css/scope/) `:scope` соответствует корневому элементу области (селектору‑якорю правила `@scope`).

## Пример

Выделим только непосредственных детей заданного блока — с помощью `:scope > …` при поиске в JS. Полная интерактивная версия — в демо ниже.

```js
const card = document.querySelector('.card')
const directChildren = card.querySelectorAll(':scope > ul > li')
directChildren.forEach((li) => li.classList.add('highlight'))
```

<iframe title=":scope — подсветка непосредственных детей" src="demos/basic/" height="460"></iframe>

## Как пишется

Синтаксис — обычный псевдокласс в селекторе:

```css
/* Внутри @scope :scope — это корень области */
@scope (.card) {
:scope { outline: 2px dashed #2E9AFF; }
:scope > h2 { color: #2E9AFF; }
}
```

В JavaScript `:scope` особенно полезен с относительными комбинаторами:

```js
// Только непосредственные дочерние <li>
el.querySelectorAll(':scope > li')

// Соседний элемент того же уровня
el.querySelectorAll(':scope + .sibling')

// Все последующие элементы того же уровня
el.querySelectorAll(':scope ~ .others')
```

## Как понять

Обычно селектор вроде `> li` в DOM‑методах нельзя написать «сам по себе», потому что нужен левый операнд — от чего вести отсчёт. `:scope` выступает как явный левый операнд и указывает, что ориентир — текущий корень поиска (элемент, на котором вызван `querySelector(All)`). Поэтому `el.querySelectorAll(':scope > li')` выбирает только непосредственных детей `el`, а не всех потомков.

В стилях [`@scope`](/css/scope/) ограничивает действие селекторов подблока. Там `:scope` ссылается на корневой элемент области — это делает селекторы внутри правила выразительнее и локальнее.

## Подсказки

💡 Используйте `:scope` для надёжного выбора «только детей» при работе с вложенными списками и компонентами.
💡 У `:scope` обычная «весомость» псевдокласса. Помните, что добавляя `:scope`, вы увеличиваете специфичность селектора.
💡 В CSS без [`@scope`](/css/scope/) `:scope` обычно совпадает с корнем документа и в шаблонных стилях встречается реже; максимальную пользу псевдокласс приносит в DOM‑поиске и внутри [`@scope`](/css/scope/).
Loading