CSS-nesten

Een van onze favoriete CSS-preprocessorfuncties is nu in de taal ingebouwd: neststijlregels.

Adam Argyle
Adam Argyle

Vóór het nesten moest elke selector expliciet worden gedeclareerd, afzonderlijk van elkaar. Dit leidt tot herhaling, stylesheet-bulk en een verspreide schrijfervaring.

Voor
.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

.nesting > .is > .awesome {
  color: deeppink;
}

Na het nesten kunnen selectors worden voortgezet en kunnen gerelateerde stijlregels daarin worden gegroepeerd.

Na
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

Probeer dit eens in de browser .

Nesten helpt ontwikkelaars door de noodzaak om selectors te herhalen te verminderen en tegelijkertijd stijlregels voor gerelateerde elementen samen te plaatsen. Het kan er ook voor zorgen dat stijlen overeenkomen met de HTML die ze targeten. Als de .nesting component in het vorige voorbeeld uit het project was verwijderd, kunt u de hele groep verwijderen in plaats van in bestanden te zoeken naar gerelateerde selectorinstanties.

Nesten kan helpen bij: - Organisatie - Het verkleinen van de bestandsgrootte - Refactoring

Nesten is beschikbaar vanaf Chrome 112 en kan ook worden geprobeerd in Safari Technical Preview 162 .

Aan de slag met CSS-nesten

In de rest van dit bericht wordt de volgende demo-sandbox gebruikt om u te helpen de selecties te visualiseren. In deze standaardstatus is niets geselecteerd en is alles zichtbaar. Door de verschillende vormen en formaten te selecteren, kunt u de syntaxis oefenen en in actie zien.

Een kleurrijk raster van kleine en grote cirkels, driehoeken en vierkanten.

In de zandbak bevinden zich cirkels, driehoeken en vierkanten. Sommige zijn klein, middelgroot of groot. Anderen zijn blauw, roze of paars. Ze bevinden zich allemaal in het .demo bevattende element. Het volgende is een voorbeeld van de HTML-elementen die u gaat targeten.

<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>

Nestvoorbeelden

Met CSS-nesten kunt u stijlen definiëren voor een element binnen de context van een andere selector.

.parent {
  color: blue;

  .child {
    color: red;
  }
}

In dit voorbeeld is de klasseselector .child genest in de klasseselector .parent . Dit betekent dat de geneste .child selector alleen van toepassing is op elementen die onderliggende elementen zijn van elementen met een .parent klasse.

Dit voorbeeld kan ook worden geschreven met het & -symbool, om expliciet aan te geven waar de bovenliggende klasse moet worden geplaatst.

.parent {
  color: blue;

  & .child {
    color: red;
  }
}

Deze twee voorbeelden zijn functioneel gelijkwaardig en de reden waarom u opties heeft, zal duidelijker worden naarmate meer geavanceerde voorbeelden in dit artikel worden onderzocht.

Het selecteren van de cirkels

Voor dit eerste voorbeeld is het de taak om stijlen toe te voegen om alleen de cirkels in de demo te vervagen en te vervagen.

Zonder nesten , CSS vandaag:

.demo .circle {
  opacity: .25;
  filter: blur(25px);
}

Met nesten zijn er twee geldige manieren:

/* & is explicitly placed in front of .circle */
.demo {
  & .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

of

/* & + " " space is added for you */
.demo {
  .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

Het resultaat , alle elementen binnen .demo met een .circle -klasse zijn vervaagd en bijna onzichtbaar:

Het kleurrijke raster van vormen heeft geen cirkels meer, ze zijn erg vaag op de achtergrond.
Probeer een demo

Selecteer eventuele driehoeken en vierkanten

Deze taak vereist het selecteren van meerdere geneste elementen, ook wel een groepskiezer genoemd.

Zonder nesting zijn er tegenwoordig twee manieren voor CSS:

.demo .triangle,
.demo .square {
  opacity: .25;
  filter: blur(25px);
}

of, met behulp van :is()

/* grouped with :is() */
.demo :is(.triangle, .square) {
  opacity: .25;
  filter: blur(25px);
}

Met nesting zijn hier twee geldige manieren:

.demo {
  & .triangle,
  & .square {
    opacity: .25;
    filter: blur(25px);
  }
}

of

.demo {
  .triangle, .square {
    opacity: .25;
    filter: blur(25px);
  }
}

Het resultaat : alleen .circle -elementen blijven binnen .demo :

Het kleurrijke raster van vormen bevat alleen nog maar cirkels, alle andere vormen zijn bijna onzichtbaar.
Probeer een demo

Grote driehoeken en cirkels selecteren

Voor deze taak is een samengestelde selector vereist, waarbij voor elementen beide klassen aanwezig moeten zijn om te kunnen worden geselecteerd.

Zonder nesten , CSS vandaag:

.demo .lg.triangle,
.demo .lg.square {
  opacity: .25;
  filter: blur(25px);
}

of

.demo .lg:is(.triangle, .circle) {
  opacity: .25;
  filter: blur(25px);
}

Met nesting zijn hier twee geldige manieren:

.demo {
  .lg.triangle,
  .lg.circle {
    opacity: .25;
    filter: blur(25px);
  }
}

of

.demo {
  .lg {
    &.triangle,
    &.circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

Het resultaat , alle grote driehoeken en cirkels zijn verborgen in .demo :

Op het kleurrijke raster zijn alleen kleine en middelgrote vormen zichtbaar.
Probeer een demo
Pro-tip met samengestelde selectors en nesten

Het & -symbool is hier uw vriend, omdat het expliciet laat zien hoe u geneste selectors kunt aansluiten. Beschouw het volgende voorbeeld:

.demo {
  .lg {
    .triangle,
    .circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

Hoewel dit een geldige manier is om te nesten, komen de resultaten niet overeen met de elementen die u mag verwachten. De reden is dat zonder & het gewenste resultaat van .lg.triangle, .lg.circle samengevoegd, het werkelijke resultaat .lg .triangle, .lg .circle zou zijn; afstammeling selecteurs .

Alle vormen selecteren behalve de roze

Deze taak vereist een negatie-functionele pseudo-klasse , waarbij elementen niet de opgegeven selector mogen hebben.

Zonder nesten , CSS vandaag:

.demo :not(.pink) {
  opacity: .25;
  filter: blur(25px);
}

Met nesting zijn hier twee geldige manieren:

.demo {
  :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

of

.demo {
  & :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

Het resultaat , alle vormen die niet roze zijn, zijn verborgen in .demo :

Het kleurrijke raster is nu monochroom en toont alleen roze vormen.
Probeer een demo
Precisie en flexibiliteit met &

Stel dat u .demo wilt targeten met de :not() -selector. & is daarvoor nodig :

.demo {
  &:not() {
    ...
  }
}

Dit combineert .demo en :not() tot .demo:not() , in tegenstelling tot het vorige voorbeeld waarvoor .demo :not() nodig was. Deze herinnering is erg belangrijk als u een :hover interactie wilt nesten.

.demo {
  &:hover {
    /* .demo:hover */
  }

  :hover {
    /* .demo :hover */
  }
}

Meer nestvoorbeelden

De CSS-specificatie voor nesten staat boordevol meer voorbeelden. Als u via voorbeelden meer over de syntaxis wilt leren, vindt u hier een breed scala aan geldige en ongeldige voorbeelden.

De volgende paar voorbeelden introduceren kort een CSS-nestfunctie, om u te helpen de breedte van de mogelijkheden die deze introduceert te begrijpen.

Nesten van @media

Het kan erg afleidend zijn om naar een ander gebied van het stylesheet te gaan om mediaqueryvoorwaarden te vinden die een selector en zijn stijlen wijzigen. Die afleiding is verdwenen dankzij het vermogen om de omstandigheden precies in de context te plaatsen.

Voor syntaxisgemak: als de geneste mediaquery alleen de stijlen voor de huidige selectorcontext wijzigt, kan een minimale syntaxis worden gebruikt.

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    font-size: 1.25rem;
  }
}

Met & expliciet kan ook:

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    &.large {
      font-size: 1.25rem;
    }
  }
}

Dit voorbeeld toont de uitgebreide syntaxis met & , terwijl ook .large -kaarten worden getarget om aan te tonen dat aanvullende nestfuncties blijven werken.

Meer informatie over het nesten van @rules .

Overal nestelen

Alle voorbeelden tot nu toe zijn voortgezet of toegevoegd aan een eerdere context. Indien nodig kunt u de context volledig wijzigen of herschikken.

.card {
  .featured & {
    /* .featured .card */
  }
}

Het & -symbool vertegenwoordigt een verwijzing naar een selectorobject (geen tekenreeks) en kan overal in een geneste selector worden geplaatst. Hij kan zelfs meerdere keren geplaatst worden:

.card {
  .featured & & & {
    /* .featured .card .card .card */
  }
}

Hoewel dit voorbeeld er wat nutteloos uitziet, zijn er zeker scenario's waarin het handig is om een ​​selectorcontext te kunnen herhalen.

Ongeldige nestvoorbeelden

Er zijn enkele scenario's voor het nesten van syntaxis die ongeldig zijn en die u wellicht zullen verbazen als u in preprocessors heeft genest.

Nesten en aaneenschakelen

Veel CSS-naamgevingsconventies voor klassen rekenen erop dat nesten selectors kan aaneenschakelen of toevoegen alsof het strings zijn. Dit werkt niet bij het nesten van CSS, omdat de selectors geen tekenreeksen zijn, maar objectreferenties.

.card {
  &--header {
    /* is not equal to ".card--header" */
  }
}

Een meer diepgaande uitleg is te vinden in de specificatie .

Lastig nestvoorbeeld

Nesten binnen selectorlijsten en :is()

Overweeg het volgende nestende CSS-blok:

.one, #two {
  .three {
    /* some styles */
  }
}

Dit is het eerste voorbeeld dat begint met een selectorlijst en vervolgens verder nestelt. Eerdere voorbeelden eindigden alleen met een selectorlijst. Er is niets ongeldig in dit nestvoorbeeld, maar er is een potentieel lastig implementatiedetail over het nesten in selectorlijsten, vooral die welke een ID-selector bevatten.

Om de bedoeling van het nesten te laten werken, zal elke selectielijst die niet de binnenste nesting is, door de browser worden omhuld met :is() . Deze omloop behoudt de groepering van de selectorlijst binnen alle geschreven contexten. Het neveneffect van deze groepering, :is(.one, #two) , is dat deze de specificiteit overneemt van de hoogste score binnen de selectors tussen haakjes. Dit is hoe :is() altijd werkt , maar het kan een verrassing zijn als je nest-syntaxis gebruikt, omdat het niet precies is wat er is geschreven. De truc samengevat; Nesten met ID's en selectorlijsten kan leiden tot selectors met een zeer hoge specificiteit.

Om het lastige voorbeeld duidelijk samen te vatten: het vorige nestblok wordt als volgt op het document toegepast:

:is(.one, #two) .three {
  /* some styles */
}

Houd een oogje in het zeil of leer uw linters om te waarschuwen wanneer ze nesten in een selectorlijst die een ID-selector gebruikt; de specificiteit van alle nestingen binnen die selectorlijst zal hoog zijn.

Nesten en declaraties combineren

Overweeg het volgende nestende CSS-blok:

.card {
  color: green;
  & { color: blue; }
  color: red;
}

De kleur van .card elementen is blue .

Eventuele onderling gemengde stijldeclaraties worden naar boven gehesen, alsof ze zijn geschreven voordat er sprake was van nesten. Meer details vindt u in de specificatie .

Er zijn manieren om dit te omzeilen. Het volgende omvat de drie kleurstijlen in & , waardoor de cascadevolgorde wordt gehandhaafd zoals de auteur mogelijk heeft bedoeld. De kleur van .card elementen is rood.

.card {
  color: green;
  & { color: blue; }
  & { color: red; }
}

Het is zelfs een goede gewoonte om stijlen die volgen op het nesten te verpakken met een & .

.card {
  color: green;

  @media (prefers-color-scheme: dark) {
    color: lightgreen;
  }

  & {
    aspect-ratio: 4/3;
  }
}

Functiedetectie

Er zijn twee geweldige manieren om CSS-nesten te detecteren: gebruik nesten of gebruik @supports om te controleren of de nesting-selector parseermogelijkheden heeft.

Een screenshot van de Codepen-demo van Bramus, waarin wordt gevraagd of uw browser CSS-nesten ondersteunt. Onder die vraag staat een groen vakje, dat steun aangeeft.

Nesten gebruiken:

html {
  .has-nesting {
    display: block;
  }

  .no-nesting {
    display: none;
  }
}

@supports gebruiken:

@supports (selector(&)) {
  /* nesting parsing available */
}

Mijn collega Bramus heeft een geweldige Codepen die deze strategie laat zien.

Foutopsporing met Chrome DevTools

De huidige ondersteuning in DevTools voor nesten is minimaal. Momenteel ziet u dat stijlen zoals verwacht worden weergegeven in het deelvenster Stijlen, maar het traceren van de nesting en de volledige selectorcontext wordt nog niet ondersteund. We hebben een ontwerp en plannen om dit transparant en duidelijk te maken.

Een screenshot van de nestende syntaxis van Chrome DevTools.

Chrome 113 is van plan extra ondersteuning te bieden voor CSS-nesten. Blijf op de hoogte.

De toekomst

CSS Nesting is alleen beschikbaar in versie 1. Versie 2 introduceert meer syntactische suiker en mogelijk minder regels om te onthouden. Er is veel vraag naar het parseren van nesten, zodat het niet beperkt is of lastige momenten kent.

Nesten is een grote verbetering van de CSS-taal. Het heeft implicaties voor het schrijven van bijna elk architectonisch aspect van CSS. Deze grote impact moet diepgaand worden onderzocht en begrepen voordat versie 2 effectief kan worden gespecificeerd.

Als laatste gedachte is hier een demo die @scope , nesting en @layer allemaal samen gebruikt. Het is allemaal heel spannend!

Een lichte kaart op een grijze achtergrond. De kaart heeft een titel en tekst, een paar actieknoppen en een afbeelding in cyberpunkstijl.