Isolar estilos a um pedaço específico do HTML sempre dependeu de convenções como BEM, de CSS Modules ou de ferramentas de build. A regra @scope traz esse isolamento para o CSS nativo: ela define um limite superior e, opcionalmente, um limite inferior, e as regras dentro dela só afetam o que está dentro desse "donut" de escopo.
O problema que o @scope resolve
Sem escopo, um seletor genérico como .card p vaza para qualquer p dentro de qualquer .card na página, inclusive cards aninhados uns dentro dos outros ou variações de componente que não deveriam ser afetadas:
.card p {
color: #444;
}
/* Se um .card estiver dentro de outro .card, essa regra
também atinge o parágrafo do card interno */
Como funciona
A sintaxe básica usa @scope com um seletor entre parênteses definindo a raiz do escopo. Dentro do bloco, & representa essa raiz:
@scope (.card) {
:scope {
border: 1px solid #ddd;
padding: 16px;
}
p {
color: #444;
}
a {
color: #12A8C3;
}
}
Aqui, p e a só recebem o estilo quando estão dentro de um elemento .card, mas continuam sendo seletores curtos e simples de escrever.
Limite inferior com "to"
O ponto mais interessante do @scope é poder definir também um limite inferior, criando um escopo em formato de "rosquinha" (donut scope) que exclui uma subárvore específica:
@scope (.card) to (.card-conteudo-externo) {
p {
color: #444;
}
}
<div class="card">
<p>Este parágrafo recebe o estilo.</p>
<div class="card-conteudo-externo">
<p>Este parágrafo NÃO recebe, pois está além do limite.</p>
</div>
</div>
Isso é útil para evitar que os estilos de um componente "vazem" para conteúdo injetado dinamicamente ou para componentes de terceiros renderizados dentro dele.
Prioridade por proximidade
Quando dois blocos @scope diferentes tentam estilizar o mesmo elemento, vence o escopo cuja raiz está mais próxima do elemento na árvore do DOM, e não a ordem em que as regras foram escritas no arquivo CSS:
@scope (.tema-claro) {
.botao {
background: #fff;
color: #111;
}
}
@scope (.card) {
.botao {
background: #12A8C3;
color: #fff;
}
}
Se um .botao estiver dentro de .card, que por sua vez está dentro de .tema-claro, vence o estilo do .card por estar mais próximo do botão, independente da ordem no arquivo.
Quando usar
- Encapsular estilos de um componente sem recorrer a nomes de classe longos (estilo BEM) só para evitar colisão.
- Evitar que estilos de um componente vazem para conteúdo injetado dinamicamente por terceiros (widgets, HTML vindo de um CMS).
- Reduzir a especificidade das regras, já que seletores dentro do
@scopepodem ser curtos sem entrar em conflito com o resto da página. - Organizar CSS de design systems onde cada componente deve ficar isolado dos demais.
Cuidados
O @scope não substitui Shadow DOM: ele isola seletores, mas não isola herança de propriedades nem impede que estilos globais (como os aplicados no body ou em *) continuem afetando os elementos dentro do escopo.
Compatibilidade
O @scope alcançou Baseline em 2025, com suporte em todas as versões atuais do Chrome, Edge, Safari e Firefox. Para projetos que ainda precisam suportar navegadores mais antigos, vale envolver o uso em um @supports (selector(&)) ou aguardar mais um pouco antes de adotar em produção.
Conclusão
O @scope resolve um problema antigo do CSS — a falta de isolamento real entre componentes — sem exigir pré-processadores, convenções de nomenclatura ou Shadow DOM. É uma peça a mais para escrever CSS mais previsível e fácil de manter em projetos grandes.
0 Comentário
Deixe seu Comentário!