Um dos nossos recursos favoritos de pré-processador de CSS agora está integrado à linguagem: o aninhamento de regras de estilo.
Antes do aninhamento, cada seletor precisava ser declarado explicitamente, separadamente um do outro. Isso leva à repetição, folha de estilo em massa e uma experiência de criação esparsa.
.nesting { color: hotpink; } .nesting > .is { color: rebeccapurple; } .nesting > .is > .awesome { color: deeppink; }
Após o aninhamento, os seletores podem ser continuados, e as regras de estilo relacionadas a ele podem ser agrupadas.
.nesting { color: hotpink; > .is { color: rebeccapurple; > .awesome { color: deeppink; } } }
Tente fazer isso no navegador.
A aninhamento ajuda os desenvolvedores ao reduzir a necessidade de repetir seletores e, ao mesmo tempo,
colocalizar regras de estilo para elementos relacionados. Isso também ajuda os estilos
a corresponder ao HTML segmentado. Se o componente .nesting
do exemplo anterior tiver sido
removido do projeto, você poderá excluir todo o grupo em vez de pesquisar
arquivos relacionados a instâncias do seletor.
O aninhamento pode ajudar com: - Organização - Reduzir o tamanho do arquivo - Refatoração
O aninhamento está disponível a partir do Chrome 112 e também para teste na Prévia técnica do Safari 162.
Começar a usar a Transição de CSS
No restante desta postagem,o sandbox de demonstração a seguir é usado para ajudar você a visualizar as seleções. Nesse estado padrão, nada é selecionado e tudo fica visível. Ao selecionar as várias formas e tamanhos, você pode praticar a sintaxe e vê-la em ação.
Dentro da sandbox há círculos, triângulos e quadrados. Algumas são pequenas, médias ou grandes. Outras são azul, rosa ou roxo. Eles estão todos dentro do elemento
que contém .demo
. Confira a seguir uma prévia dos elementos HTML que vão ser
segmentados.
<div class="demo">
<div class="sm triangle pink"></div>
<div class="sm triangle blue"></div>
<div class="square blue"></div>
<div class="sm square pink"></div>
<div class="sm square blue"></div>
<div class="circle pink"></div>
…
</div>
Exemplos de aninhamento
O aninhamento de CSS permite definir estilos para um elemento dentro do contexto de outro seletor.
.parent {
color: blue;
.child {
color: red;
}
}
Neste exemplo, o seletor de classe .child
está aninhado
no seletor de classe .parent
. Isso significa que o seletor .child
aninhado será
aplicado apenas a elementos filhos de elementos com uma classe .parent
.
Esse exemplo também pode ser escrito usando o símbolo &
, para indicar
explicitamente onde a classe pai precisa ser colocada.
.parent {
color: blue;
& .child {
color: red;
}
}
Esses dois exemplos são funcionalmente equivalentes, e o motivo para você ter opções se tornará mais claro à medida que exemplos mais avançados forem explorados neste artigo.
Seleção dos círculos
Neste primeiro exemplo, a tarefa é adicionar estilos para esmaecer e desfocar apenas os círculos dentro da demonstração.
Sem aninhamento, CSS atual:
.demo .circle {
opacity: .25;
filter: blur(25px);
}
Com o aninhamento, há duas maneiras válidas:
/* & is explicitly placed in front of .circle */
.demo {
& .circle {
opacity: .25;
filter: blur(25px);
}
}
ou
/* & + " " space is added for you */
.demo {
.circle {
opacity: .25;
filter: blur(25px);
}
}
Como resultado, todos os elementos dentro de .demo
com uma classe .circle
serão
desfocados e quase invisíveis:
![A grade colorida de formas não tem mais círculos,
eles são muito fracos no plano de fundo.](https://developer.chrome.com/static/docs/css-ui/css-nesting/image/the-colorful-grid-shapes-f1beac5a4a5be.png?authuser=6&hl=pt)
Selecionando triângulos e quadrados
Essa tarefa requer a seleção de vários elementos aninhados, também chamado de seletor de grupo.
Sem aninhamento, o CSS atual oferece duas maneiras:
.demo .triangle,
.demo .square {
opacity: .25;
filter: blur(25px);
}
ou usando :is()
/* grouped with :is() */
.demo :is(.triangle, .square) {
opacity: .25;
filter: blur(25px);
}
Com o aninhamento, há duas maneiras válidas:
.demo {
& .triangle,
& .square {
opacity: .25;
filter: blur(25px);
}
}
ou
.demo {
.triangle, .square {
opacity: .25;
filter: blur(25px);
}
}
Como resultado, apenas os elementos .circle
permanecem dentro de .demo
:
![A grade colorida de formas fica apenas com círculos,
e todas as outras formas são quase invisíveis.](https://developer.chrome.com/static/docs/css-ui/css-nesting/image/the-colorful-grid-shapes-5baea09e41652.png?authuser=6&hl=pt)
Seleção de triângulos e círculos grandes
Essa tarefa requer um seletor composto em que os elementos precisam ter as duas classes presentes para serem selecionados.
Sem aninhamento, CSS atual:
.demo .lg.triangle,
.demo .lg.square {
opacity: .25;
filter: blur(25px);
}
ou
.demo .lg:is(.triangle, .circle) {
opacity: .25;
filter: blur(25px);
}
Com o aninhamento, há duas maneiras válidas:
.demo {
.lg.triangle,
.lg.circle {
opacity: .25;
filter: blur(25px);
}
}
ou
.demo {
.lg {
&.triangle,
&.circle {
opacity: .25;
filter: blur(25px);
}
}
}
Como resultado, todos os triângulos e círculos grandes estão escondidos dentro de .demo
:
![A grade colorida tem apenas formas pequenas e médias visíveis.](https://developer.chrome.com/static/docs/css-ui/css-nesting/image/the-colorful-grid-has-sm-5a9e56b5c62b4.png?authuser=6&hl=pt)
Dica profissional com seletores compostos e aninhamento
O símbolo &
é seu amigo aqui, porque mostra explicitamente como adicionar seletores
aninhados. Confira o exemplo abaixo:
.demo {
.lg {
.triangle,
.circle {
opacity: .25;
filter: blur(25px);
}
}
}
Embora seja uma maneira válida de aninhar, os resultados não corresponderão aos elementos esperados.
O motivo é que, sem &
para especificar o resultado desejado de .lg.triangle,
.lg.circle
combinado, o resultado real seria .lg .triangle, .lg
.circle
; seletores descendentes.
Selecionar todas as formas exceto as rosas
Essa tarefa requer uma pseudoclasse funcional de negação, em que os elementos não podem ter o seletor especificado.
Sem aninhamento, CSS atual:
.demo :not(.pink) {
opacity: .25;
filter: blur(25px);
}
Com o aninhamento, há duas maneiras válidas:
.demo {
:not(.pink) {
opacity: .25;
filter: blur(25px);
}
}
ou
.demo {
& :not(.pink) {
opacity: .25;
filter: blur(25px);
}
}
O resultado, todas as formas que não são rosa ficam ocultas dentro de .demo
:
![A grade colorida agora é monocromática, mostrando apenas formas rosas.](https://developer.chrome.com/static/docs/css-ui/css-nesting/image/the-colorful-grid-is-mon-0203fb32e8aea.png?authuser=6&hl=pt)
Precisão e flexibilidade com o &
Digamos que você queira segmentar .demo
com o seletor :not()
. &
é obrigatório para
isso:
.demo {
&:not() {
...
}
}
Isso compõe .demo
e :not()
a .demo:not()
, ao contrário do exemplo
anterior, que precisava de .demo :not()
. Esse lembrete é muito importante quando
querem aninhar uma interação :hover
.
.demo {
&:hover {
/* .demo:hover */
}
:hover {
/* .demo :hover */
}
}
Mais exemplos de aninhamento
A especificação CSS para aninhamento inclui mais exemplos. Se você quiser saber mais sobre a sintaxe por meio de exemplos, vamos abordar uma ampla variedade de exemplos válidos e inválidos.
Os próximos exemplos apresentarão brevemente um recurso de aninhamento de CSS para ajudar você a entender a amplitude de recursos que ele apresenta.
Transição de @media
Pode ser uma distração se mover para outra área da folha de estilo e encontrar condições de consulta de mídia que modifiquem um seletor e os estilos dele. Essa distração acabou com a capacidade de aninhar as condições dentro do contexto.
Para facilitar a sintaxe, se a consulta de mídia aninhada só modificar os estilos do contexto do seletor atual, uma sintaxe mínima poderá ser usada.
.card {
font-size: 1rem;
@media (width >= 1024px) {
font-size: 1.25rem;
}
}
O uso explícito de &
também pode ser utilizado:
.card {
font-size: 1rem;
@media (width >= 1024px) {
&.large {
font-size: 1.25rem;
}
}
}
Este exemplo mostra a sintaxe expandida com &
, além de direcionar os cards .large
para demonstrar que outros recursos de aninhamento continuam funcionando.
Saiba mais sobre o aninhamento de @rules.
Aninhamento em qualquer lugar
Todos os exemplos até aqui continuaram ou foram anexados a um contexto anterior. É possível mudar ou reorganizar completamente o contexto, se necessário.
.card {
.featured & {
/* .featured .card */
}
}
O símbolo &
representa uma referência a um objeto seletor (não uma string) e
pode ser colocado em qualquer lugar de um seletor aninhado. Ela pode até ser colocada
várias vezes:
.card {
.featured & & & {
/* .featured .card .card .card */
}
}
Embora esse exemplo pareça um pouco inútil, certamente há cenários em que a capacidade de repetir um contexto de seletor é útil.
Exemplos de aninhamento inválidos
Alguns cenários de sintaxe de aninhamento são inválidos e podem surpreendê-lo se você estiver aninhando em pré-processadores.
Aninhamento e concatenação
Muitas convenções de nomenclatura de classes CSS contam com a capacidade do aninhamento de concatenar ou anexar seletores como se fossem strings. Isso não funciona no aninhamento de CSS, já que os seletores não são strings, são referências de objetos.
.card {
&--header {
/* is not equal to ".card--header" */
}
}
Uma explicação mais detalhada pode ser encontrada na especificação.
Exemplo complicado de aninhamento
Aninhamento nas listas de seletores e :is()
Considere o seguinte bloco CSS de aninhamento:
.one, #two {
.three {
/* some styles */
}
}
Esse é o primeiro exemplo que começa com uma lista de seletores e continua a aninhamento. Os exemplos anteriores tinham terminado apenas com uma lista de seletores. Não há nada inválido neste exemplo de aninhamento, mas há um detalhe de implementação potencialmente complicado sobre o aninhamento dentro de listas de seletores, especialmente aqueles que incluem um seletor de ID.
Para que o intent do aninhamento funcione, qualquer lista de seletores que não seja o mais interno será unida a :is()
pelo navegador. Esse ajuste mantém o agrupamento da lista de seletores em qualquer contexto criado. O efeito colateral desse agrupamento, :is(.one, #two)
, é que ele adota a especificidade da pontuação mais alta nos seletores entre parênteses. É assim que :is()
sempre funciona, mas pode ser uma surpresa ao usar a sintaxe de aninhamento, porque não é exatamente o que foi criado. O truque resumido: o aninhamento com IDs e listas de seletores pode levar a seletores de especificidade muito alta.
Para recapitular claramente o exemplo complicado, o bloco de aninhamento anterior será aplicado ao documento desta forma:
:is(.one, #two) .three {
/* some styles */
}
Fique atento ou ensine os lints a avisarem quando você fizer o aninhamento dentro de uma lista de seletores que usa um seletor de ID. A especificidade de todo o aninhamento nessa lista de seletores será alta.
Como combinar aninhamento e declarações
Considere o seguinte bloco CSS de aninhamento:
.card {
color: green;
& { color: blue; }
color: red;
}
A cor dos elementos .card
será blue
.
Todas as declarações de estilo misturado são elevadas para a parte superior, como se fossem criadas antes da ocorrência de qualquer aninhamento. Confira mais detalhes nas especificações.
Existem maneiras de evitar isso. O exemplo a seguir une os três estilos de cores em &
, que
mantém a ordem em cascata conforme a intenção do autor. A cor dos
elementos .card
será vermelha.
.card {
color: green;
& { color: blue; }
& { color: red; }
}
Na verdade, é recomendável unir todos os estilos que seguem o aninhamento com uma &
.
.card {
color: green;
@media (prefers-color-scheme: dark) {
color: lightgreen;
}
& {
aspect-ratio: 4/3;
}
}
Detecção de recursos
Há duas ótimas maneiras de detectar o aninhamento de CSS: usar o aninhamento ou usar
@supports
para verificar o recurso de análise do seletor de aninhamento.
Como usar o aninhamento:
html {
.has-nesting {
display: block;
}
.no-nesting {
display: none;
}
}
Utilizando @supports
:
@supports (selector(&)) {
/* nesting parsing available */
}
Bramus (link em inglês) tem um ótimo Codepen que mostra essa estratégia.
Como depurar com o Chrome DevTools
O suporte atual para aninhamento no DevTools é mínimo. No momento, os estilos são representados no painel "Estilos" como esperado, mas o rastreamento do aninhamento e o contexto do seletor completo ainda não é compatível. Temos um design e planos para tornar isso transparente e claro.
O Chrome 113 planeja ter mais suporte para o aninhamento de CSS. Fique por dentro das novidades.
O futuro
A Transição de CSS está somente na versão 1. A versão 2 apresenta mais facilidade sintática e possivelmente menos regras para memorizar. Há muita demanda para que a análise do aninhamento não seja limitada ou tenha momentos complicados.
A Transição é uma grande melhoria na linguagem CSS. Isso tem implicações de autor em quase todos os aspectos arquitetônicos dos CSS. Esse grande impacto precisa ser profundamente explorado e compreendido antes que a versão 2 possa ser efetivamente especificada.
Como pensamento final, veja uma demonstração (em inglês)
que usa @scope
, aninhamento e @layer
juntos. É tudo muito emocionante!