Клавиша / esc

@scope

Ограничиваем область действия стилей внутри поддерева DOM и избегаем конфликтов между компонентами.

Время чтения: 5 мин

Кратко

Скопировано

Директива @scope ограничивает область действия CSS-правил внутри части DOM-дерева. Стили применяются только к элементам внутри заданного контейнера, но не применяются к элементам, попадающим в исключаемую часть (to) и их потомкам.

Пример

Скопировано

Заголовок внутри .article окрашивается в синий, заголовок-подпись внутри .media — нет (.media задана как граница to), заголовок в .aside тоже не затронут, он вне корня @scope:

        
          
          <section class="article">  <h2 class="title">Заголовок статьи</h2>  <figure class="media">    <img src="cat.jpg" alt="Котик" />    <figcaption class="title">Подпись к изображению</figcaption>  </figure>  <p>Текст…</p></section><section class="aside">  <h2 class="title">Боковая колонка</h2>  <p>Текст…</p></section>
          <section class="article">
  <h2 class="title">Заголовок статьи</h2>
  <figure class="media">
    <img src="cat.jpg" alt="Котик" />
    <figcaption class="title">Подпись к изображению</figcaption>
  </figure>
  <p>Текст…</p>
</section>

<section class="aside">
  <h2 class="title">Боковая колонка</h2>
  <p>Текст…</p>
</section>

        
        
          
        
      
        
          
          @scope (.article) to (.media) {  .title {    color: #2E9AFF;  }}
          @scope (.article) to (.media) {
  .title {
    color: #2E9AFF;
  }
}

        
        
          
        
      
Открыть демо в новой вкладке

Как пишется

Скопировано

Явные корень и граница

Скопировано

Корень и граница задаются в скобках после @scope:

        
          
          /* Граница необязательна */@scope (.component) {  /* стили применяются ко всем потомкам .component */}/* С границей */@scope (<корень>) to (<граница>) {  /* стили */}
          /* Граница необязательна */
@scope (.component) {
  /* стили применяются ко всем потомкам .component */
}

/* С границей */
@scope (<корень>) to (<граница>) {
  /* стили */
}

        
        
          
        
      

Корень — один или несколько селекторов, от которых начинается область. Через запятую можно указать сразу несколько, для каждого создаётся своя отдельная область:

        
          
          @scope (.article, .news, .post) {  h2 {    color: tomato;  }}
          @scope (.article, .news, .post) {
  h2 {
    color: tomato;
  }
}

        
        
          
        
      

Граница (to) — селекторы, которые вырезаются из области. Попавшие под них элементы и их потомки не получают стили из этой области.

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

        
          
          /*  figure становится границей области  только если .article-body находится внутри .feature*/@scope (.article-body) to (.feature :scope figure) {  img {    border: 4px solid #2E9AFF;  }}
          /*
  figure становится границей области
  только если .article-body находится внутри .feature
*/
@scope (.article-body) to (.feature :scope figure) {
  img {
    border: 4px solid #2E9AFF;
  }
}

        
        
          
        
      
        
          
          <article class="feature">  <section class="article-body">    <img src="photo.jpg" alt="Фото" />    <figure>      <img src="photo2.jpg" alt="Фото в фигуре" />    </figure>  </section></article>
          <article class="feature">
  <section class="article-body">
    <img src="photo.jpg" alt="Фото" />

    <figure>
      <img src="photo2.jpg" alt="Фото в фигуре" />
    </figure>
  </section>
</article>

        
        
          
        
      

Слева .article-body находится внутри .featurefigure становится границей, рамку получает только первое изображение. Справа .article-body стоит без .feature — граница не активируется, рамку получают оба.

Открыть демо в новой вкладке

Внутри @scope работает псевдокласс :scope — он ссылается на корневой элемент области:

        
          
          @scope (.widget) {  :scope {    display: block;  }  :scope > .title {    font-weight: 600;  }}
          @scope (.widget) {
  :scope {
    display: block;
  }

  :scope > .title {
    font-weight: 600;
  }
}

        
        
          
        
      

Встроенный <style>

Скопировано

@scope { ... } можно поместить в тег <style> прямо в разметке нужного контейнера. Корнём области автоматически становится ближайший предок, содержащий этот <style>:

        
          
          <article class="card">  <style>    @scope {      .title { color: rebeccapurple; }    }  </style>  <h3 class="title">Новость</h3>  <p>Текст…</p>  <footer class="card__footer">…</footer></article>
          <article class="card">
  <style>
    @scope {
      .title { color: rebeccapurple; }
    }
  </style>
  <h3 class="title">Новость</h3>
  <p>Текст…</p>
  <footer class="card__footer"></footer>
</article>

        
        
          
        
      

Специфичность и вложенные конструкции

Скопировано

@scope не изменяет специфичность селекторов, они участвуют в каскаде как обычно:

        
          
          .card .title {  color: red;}@scope (.card) {  .title {    color: blue;  }}
          .card .title {
  color: red;
}

@scope (.card) {
  .title {
    color: blue;
  }
}

        
        
          
        
      

.card .title имеет более высокую специфичность, чем .title, заголовок останется красным.

Внутри @scope работают и другие CSS-конструкции. Например, @media:

        
          
          @scope (.card) {  @media (width > 700px) {    .title {      font-size: 2rem;    }  }}
          @scope (.card) {
  @media (width > 700px) {
    .title {
      font-size: 2rem;
    }
  }
}

        
        
          
        
      

Правило применяется только к .card, но дополнительно зависит от условия медиазапроса.

Как понять

Скопировано

@scope — это способ ограничить CSS определённым блоком страницы. Например, карточкой или виджетом. Стили внутри такого блока не влияют на остальные части страницы и не требуют усложнения селекторов или переименования классов. Это помогает:

  • изолировать стили отдельных блоков интерфейса (например, карточек, статей, виджетов);
  • исключать части блока из области применения через to (...), чтобы стили не затрагивали эти элементы и их потомков;
  • уменьшать конфликты CSS без повышения специфичности.

При этом важно понимать, что @scope не создаёт полной изоляции, как, например, Shadow DOM. Он ограничивает только применение селекторов, но не влияет на наследование CSS.

Например, если внутри области есть вложенный элемент, он может получить стили через наследование:

        
          
          <section class="card">  <div class="inner">    Текст внутри вложенного элемента  </div></section>
          <section class="card">
  <div class="inner">
    Текст внутри вложенного элемента
  </div>
</section>

        
        
          
        
      
        
          
          @scope (.card) {  .card {    color: red;  }}
          @scope (.card) {
  .card {
    color: red;
  }
}

        
        
          
        
      

В этом случае текст внутри .inner тоже станет красным, потому что color — это наследуемое свойство. @scope ограничил селектор, но не отменил механизм наследования CSS.

Подсказки

Скопировано

💡 Избегайте слишком широких корней области (например, main), так как это увеличивает вероятность случайных пересечений стилей. Лучше использовать узкие контейнеры вроде .component, чтобы изолировать поведение блока.
💡 Для виджетов, внедряемых в сторонние страницы, вариант со встроенным <style> ... @scope {} ... </style> особенно удобен.
💡 Используйте :where() для базовых (служебных) стилей, которые не должны увеличивать специфичность и легко переопределяются другими правилами, к примеру:

        
          
          @scope (.card) {  :where(.title) {    margin: 0;  }}
          @scope (.card) {
  :where(.title) {
    margin: 0;
  }
}

        
        
          
        
      

Здесь :where() имеет нулевую специфичность, поэтому такие стили проще переопределять.

Поддержка в браузерах:
  • Chrome 118, поддерживается
  • Edge 118, поддерживается
  • Firefox 146, поддерживается
  • Safari 17.4, поддерживается
О Baseline