Duas sintaxes concorrentes precisam da sua ajuda para determinar qual delas deve ser promovida a um candidato de especificação.
O aninhamento de CSS é uma adição de sintaxe conveniente que permite que o CSS seja adicionado dentro de um conjunto de regras. Se você já usou SCSS, Less ou Stylus, provavelmente já viu algumas variações disso:
.nesting {
color: hotpink;
> .is {
color: rebeccapurple;
> .awesome {
color: deeppink;
}
}
}
Que, depois de ser compilado em CSS normal pelo pré-processador, se transforma em CSS normal assim:
.nesting {
color: hotpink;
}
.nesting > .is {
color: rebeccapurple;
}
.nesting > .is > .awesome {
color: deeppink;
}
Uma versão oficial do CSS dessa sintaxe está sendo considerada, e temos uma divisão de preferências que gostaríamos de usar a ajuda da comunidade para quebrar o empate. O restante desta postagem vai apresentar as opções de sintaxe para que você possa se sentir informado para fazer uma pesquisa no final.
Por que o exemplo de aninhamento exato mostrado acima não pode ser a sintaxe para aninhamento de CSS?
Há alguns motivos para a sintaxe de aninhamento mais conhecida não ser usada como está:
Análise ambígua
Alguns seletores aninhados podem parecer exatamente como propriedades e pré-processadores e podem resolvê-los e gerenciá-los no momento da criação. Os mecanismos do navegador não terão as mesmas características, e os seletores nunca poderão ser interpretados de forma imprecisa.Conflitos de análise de pré-processadores
A maneira CSS de aninhar não pode quebrar os pré-processadores ou os fluxos de trabalho de aninhamento de desenvolvedores. Isso seria perturbador e desconsiderado para esses ecossistemas e comunidades.Aguardando
:is()
A aninhação básica não precisa de:is()
, mas a aninhação mais complexa precisa. Consulte o Exemplo 3 para uma introdução simples às listas de seletores e ao aninhamento. Imagine que a lista de seletores estivesse no meio de um seletor em vez de no início. Nesses casos,:is()
é necessário para agrupar os seletores no meio de outro seletor.
Visão geral do que estamos comparando
Queremos fazer o aninhamento de CSS corretamente, e com esse espírito, estamos incluindo a comunidade. As seções a seguir ajudarão a descrever as três versões possíveis que estamos avaliando. Em seguida, vamos analisar alguns exemplos de uso para comparação e, no final, haverá uma pesquisa rápida perguntando qual você preferiu.
Opção 1: @nest
Essa é a sintaxe especificada atualmente em Aninhamento de CSS 1. Ele oferece uma maneira conveniente de aninhar
estilos de adição iniciando novos seletores aninhados com &
. Ele também oferece
@nest
como uma maneira de colocar o contexto &
em qualquer lugar dentro de um novo seletor, como
quando você não está apenas anexando assuntos. Ele é flexível e mínimo, mas, em
troca, você precisa lembrar de @nest
ou &
, dependendo do caso de uso.
Opção 2: @nest restrito
Essa é uma alternativa mais rígida, em uma tentativa de reduzir a despesa mencionada de
lembrar dois métodos de aninhamento. Essa sintaxe restrita permite apenas que o aninhamento ocorra
após @nest
. Portanto, não há um padrão de conveniência de adição somente. Removendo
a ambiguidade de escolha, criando uma maneira fácil de lembrar de aninhar, mas sacrificando
a rigidez em favor da convenção.
Opção 3: colchetes
Para evitar a sintaxe dupla ou a desordem extra envolvida nas propostas de @nest
, Miriam Suzanne e Elika Etemad propuseram uma sintaxe alternativa
que depende de outros colchetes. Isso proporciona clareza de sintaxe,
com apenas dois caracteres extras e sem novas regras de at. Ele também permite que regras aninhadas
sejam agrupadas pelo tipo de anilhamento necessário, como uma forma de simplificar
vários seletores aninhados de maneira semelhante.
Exemplo 1: anilhamento direto
@nest
.foo {
color: #111;
& .bar {
color: #eee;
}
}
@nest sempre
.foo {
color: #111;
@nest & .bar {
color: #eee;
}
}
chaves
.foo {
color: #111;
{
& .bar {
color: #eee;
}
}
}
CSS equivalente
.foo {
color: #111;
}
.foo .bar {
color: #eee;
}
Exemplo 2: aninhamento composto
@nest
.foo {
color: blue;
&.bar {
color: red;
}
}
@nest sempre
.foo {
color: blue;
@nest &.bar {
color: red;
}
}
chaves
.foo {
color: blue;
{
&.bar {
color: red;
}
}
}
CSS equivalente
.foo {
color: blue;
}
.foo.bar {
color: red;
}
Exemplo 3: listas de seletores e aninhamento
@nest
.foo, .bar {
color: blue;
& + .baz,
&.qux {
color: red;
}
}
@nest sempre
.foo, .bar {
color: blue;
@nest & + .baz,
&.qux {
color: red;
}
}
chaves
.foo, .bar {
color: blue;
{
& + .baz,
&.qux {
color: red;
}
}
}
CSS equivalente
.foo, .bar {
color: blue;
}
:is(.foo, .bar) + .baz,
:is(.foo, .bar).qux {
color: red;
}
Exemplo 4: vários níveis
@nest
figure {
margin: 0;
& > figcaption {
background: lightgray;
& > p {
font-size: .9rem;
}
}
}
@nest sempre
figure {
margin: 0;
@nest & > figcaption {
background: lightgray;
@nest & > p {
font-size: .9rem;
}
}
}
chaves
figure {
margin: 0;
{
& > figcaption {
background: lightgray;
{
& > p {
font-size: .9rem;
}
}
}
}
}
CSS equivalente
figure {
margin: 0;
}
figure > figcaption {
background: hsl(0 0% 0% / 50%);
}
figure > figcaption > p {
font-size: .9rem;
}
Exemplo 5: aninhamento de pai ou mudança de assunto
@nest
.foo {
color: red;
@nest .parent & {
color: blue;
}
}
@nest sempre
.foo {
color: red;
@nest .parent & {
color: blue;
}
}
chaves
.foo {
color: red;
{
.parent & {
color: blue;
}
}
}
CSS equivalente
.foo {
color: red;
}
.parent .foo {
color: blue;
}
Exemplo 6: misturar anilhamento direto e pai
@nest
.foo {
color: blue;
@nest .bar & {
color: red;
&.baz {
color: green;
}
}
}
@nest sempre
.foo {
color: blue;
@nest .bar & {
color: red;
@nest &.baz {
color: green;
}
}
}
chaves
.foo {
color: blue;
{
.bar & {
color: red;
{
&.baz {
color: green;
}
}
}
}
}
CSS equivalente
.foo {
color: blue;
}
.bar .foo {
color: red;
}
.bar .foo.baz {
color: green;
}
Exemplo 7: aninhamento de consultas de mídia
@nest
.foo {
display: grid;
@media (width => 30em) {
grid-auto-flow: column;
}
}
ou explicitamente / estendido
.foo {
display: grid;
@media (width => 30em) {
& {
grid-auto-flow: column;
}
}
}
@nest always (é sempre explícito)
.foo {
display: grid;
@media (width => 30em) {
@nest & {
grid-auto-flow: column;
}
}
}
chaves
.foo {
display: grid;
@media (width => 30em) {
grid-auto-flow: column;
}
}
ou explicitamente / estendido
.foo {
display: grid;
@media (width => 30em) {
& {
grid-auto-flow: column;
}
}
}
CSS equivalente
.foo {
display: grid;
}
@media (width => 30em) {
.foo {
grid-auto-flow: column;
}
}
Exemplo 8: grupos aninhados
@nest
fieldset {
border-radius: 10px;
&:focus-within {
border-color: hotpink;
}
& > legend {
font-size: .9em;
}
& > div {
& + div {
margin-block-start: 2ch;
}
& > label {
line-height: 1.5;
}
}
}
@nest sempre
fieldset {
border-radius: 10px;
@nest &:focus-within {
border-color: hotpink;
}
@nest & > legend {
font-size: .9em;
}
@nest & > div {
@nest & + div {
margin-block-start: 2ch;
}
@nest & > label {
line-height: 1.5;
}
}
}
chaves
fieldset {
border-radius: 10px;
{
&:focus-within {
border-color: hotpink;
}
}
> {
legend {
font-size: .9em;
}
div {
+ div {
margin-block-start: 2ch;
}
> label {
line-height: 1.5;
}
}}
}
}
CSS equivalente
fieldset {
border-radius: 10px;
}
fieldset:focus-within {
border-color: hotpink;
}
fieldset > legend {
font-size: .9em;
}
fieldset > div + div {
margin-block-start: 2ch;
}
fieldset > div > label {
line-height: 1.5;
}
Exemplo 9: grupo de aninhamento complexo "Kitchen Sink"
@nest
dialog {
border: none;
&::backdrop {
backdrop-filter: blur(25px);
}
& > form {
display: grid;
& > :is(header, footer) {
align-items: flex-start;
}
}
@nest html:has(&[open]) {
overflow: hidden;
}
}
@nest sempre
dialog {
border: none;
@nest &::backdrop {
backdrop-filter: blur(25px);
}
@nest & > form {
display: grid;
@nest & > :is(header, footer) {
align-items: flex-start;
}
}
@nest html:has(&[open]) {
overflow: hidden;
}
}
chaves
dialog {
border: none;
{
&::backdrop {
backdrop-filter: blur(25px);
}
& > form {
display: grid;
{
& > :is(header, footer) {
align-items: flex-start;
}
}
}
}
{
html:has(&[open]) {
overflow: hidden;
}
}
}
CSS equivalente
dialog {
border: none;
}
dialog::backdrop {
backdrop-filter: blur(25px);
}
dialog > form {
display: grid;
}
dialog > form > :is(header, footer) {
align-items: flex-start;
}
html:has(dialog[open]) {
overflow: hidden;
}
Hora de votar
Esperamos que você tenha considerado essa uma comparação justa e um exemplo das opções de sintaxe que estamos avaliando. Analise com atenção e informe sua preferência abaixo. Agradecemos por nos ajudar a avançar o aninhamento de CSS para uma sintaxe que todos vamos conhecer e amar.