Cascadelagen (de @layer
CSS-regel ) komen naar Chromium 99, Firefox 97 en Safari 15.4 Bèta. Ze maken een explicietere controle over uw CSS-bestanden mogelijk om stijlspecifieke conflicten te voorkomen. Dit is vooral handig voor grote codebases, ontwerpsystemen en bij het beheren van stijlen van derden in applicaties.
Door uw CSS op een duidelijke manier in lagen te plaatsen, voorkomt u onverwachte stijloverschrijvingen en bevordert u een betere CSS-architectuur.
CSS-specificiteit en de cascade
CSS-specificiteit is hoe CSS beslist welke stijlen op welke elementen moeten worden toegepast. De verschillende selectors die u kunt gebruiken, bepalen de specificiteit van elke stijlregel. Elementen zijn bijvoorbeeld minder specifiek dan klassen of attributen, die op hun beurt minder specifiek zijn dan ID's. Dit is een essentieel onderdeel van het leren van CSS.
Mensen wenden zich tot CSS-naamgevingsconventies zoals BEM om te voorkomen dat de specificiteit onbedoeld wordt overschreven. Door alles een enkele klassenaam te geven, wordt alles op hetzelfde specificiteitsvlak geplaatst. Het is echter niet altijd mogelijk om zulke georganiseerde stijlen te behouden, vooral niet als je werkt met code en ontwerpsystemen van derden.
Cascadelagen zijn bedoeld om dit probleem op te lossen. Ze introduceren een nieuwe laag in de CSS- cascade . Bij gelaagde stijlen is de prioriteit van een laag altijd belangrijker dan de specificiteit van een selector .
De selector .post a.link
heeft bijvoorbeeld een hogere specificiteit dan .card a
. Als u probeert een link in een kaart of in een bericht op te maken, zult u merken dat de specifiekere selector wordt toegepast.
Door @layer
te gebruiken, kunt u explicieter zijn over de stijlspecificiteit van elke stijl, en ervoor zorgen dat de stijlen van uw kaartlink de stijlen van de postlink overschrijven, ook al zou de specificiteit numeriek lager kunnen zijn als al uw CSS zich op hetzelfde vlak bevond. Dit komt door de cascadevoorrang. Gelaagde stijlen creëren nieuwe cascade-"vlakken".
@layer
in actie
Dit voorbeeld toont de kracht van cascadelagen, met behulp van @layer
. Er worden verschillende links getoond: sommige zonder dat er extra klassenamen zijn toegepast, één met een .link
klasse en één met een .pink
-klasse. De CSS voegt vervolgens drie lagen toe: base
, typography
en utilities
, als volgt:
@layer base {
a {
font-weight: 800;
color: red; /* ignored */
}
.link {
color: blue; /* ignored */
}
}
@layer typography {
a {
color: green; /* styles *all* links */
}
}
@layer utilities {
.pink {
color: hotpink; /* styles *all* .pink's */
}
}
Uiteindelijk zijn alle schakels groen of roze. Dit komt omdat: hoewel .link
een hogere specificiteit op selectorniveau heeft dan a
, er een kleurstijl is op a
in een @layer
met hogere prioriteit. a { color: green }
overschrijft .link { color: blue }
wanneer de groene regel zich in een laag na de blauwe regel bevindt.
De prioriteit van de laag overtreft de specificiteit van het element.
Lagen organiseren
U kunt lagen rechtstreeks op de pagina ordenen, zoals hierboven weergegeven, of u kunt ze bovenaan een bestand ordenen.
De laagvolgorde wordt bepaald wanneer elke laagnaam voor het eerst in uw code verschijnt.
Dat betekent dat als u het volgende bovenaan het bestand toevoegt, de links allemaal rood verschijnen, en de link met class .link
blauw:
@layer utilities, typography, base;
Dit komt omdat de volgorde van de lagen nu is omgekeerd, waarbij de hulpprogramma's op de eerste plaats komen te staan en de basis op de laatste plaats. De stijlregels in de base
zullen dus altijd een hogere specificiteit hebben dan de stijlregels in de typografielaag. Het worden geen groene schakels meer, maar rode of blauwe.
Het organiseren van import
Een andere manier om @layer
te gebruiken is met importbestanden. U kunt dit rechtstreeks doen wanneer u stijlen importeert, met behulp van een layer()
functie, zoals in het volgende voorbeeld:
/* Base */
@import '../styles/base/normalize.css' layer(base); /* normalize or rest file */
@import '../styles/base/base.css' layer(base); /* body and base styles */
@import '../styles/base/theme.css' layer(theme); /* theme variables */
@import '../styles/base/typography.css' layer(theme); /* theme typography */
@import '../styles/base/utilities.css' layer(utilities); /* base utilities */
/* Layouts */
@import '../styles/components/post.css' layer(layouts); /* post layout */
/* Components */
@import '../styles/components/cards.css' layer(components); /* imports card */
@import '../styles/components/footer.css' layer(components); /* footer component */
Het bovenstaande codefragment heeft drie lagen: base
, layouts
en components
. De normalisatie-, thema- en typografiebestanden in base
, met een post
in layouts
, en cards
en footer
beide in components
. Bij het importeren van het bestand worden de lagen geïnstantieerd met behulp van de laagfunctie. Een alternatieve aanpak zou zijn om uw lagen bovenaan het bestand te ordenen en ze vóór elke import te declareren:
@layer base,
theme,
layouts,
components,
utilities;
De volgorde waarin u uw stijlen @import
, is niet van belang voor de laagvolgorde, omdat deze al is vastgelegd bij de eerste instantie van de laagnaam. Dat is een zorg minder. U kunt geïmporteerde bestanden nog steeds op specifieke lagen instellen, maar de volgorde is al vastgelegd.
Lagen en de cascade
Laten we een stap terug doen en kijken waar lagen worden gebruikt in relatie tot de bredere cascade:
De volgorde van prioriteit is als volgt:
- User Agent normaal (laagste prioriteit)
- Lokale gebruiker @layer
- Lokale gebruiker normaal
- Auteur @lagen
- Auteur normaal
- Auteur !belangrijk
- Auteur @layer !belangrijk
- Lokale gebruiker!belangrijk
- User Agent !belangrijk** (hoogste prioriteit)
Het zal je hier misschien opvallen dat @layer !important
-stijlen zijn omgekeerd. In plaats van minder specifiek te zijn dan niet-gelaagde (normale) stijlen, hebben ze een hogere prioriteit. Dit komt door de manier waarop !important
werkt in de cascade: het verbreekt de normale cascadering in uw stylesheets en keert de normale specificiteit op laagniveau om (voorrang).
Geneste lagen
Lagen kunnen ook in andere lagen worden genest. Het volgende voorbeeld komt uit de Cascade Layers-uitleg van Miriam Suzanne:
@layer default {
p { max-width: 70ch; }
}
@layer framework {
@layer default {
p { margin-block: 0.75em; }
}
p { margin-bottom: 1em; }
}
In het bovenstaande codefragment heeft u toegang tot framework.default
met behulp van een .
als een betekenaar van de default
die binnen framework
is genest. Je kunt dit ook in een beknopter formaat schrijven:
@layer framework.default {
p { margin-block: 0.75em }
}
De resulterende lagen en laagvolgorde zijn:
- standaard
-
framework.default
-
framework
ongelaagd - ongelaagd
Dingen om op te letten
Cascadelagen kunnen geweldig zijn als u ze op de juiste manier gebruikt, maar ze kunnen ook voor extra verwarring en onverwachte resultaten zorgen. Let op het volgende als u met cascadelagen werkt:
Regel 1: Gebruik @layer
niet voor scoping
Cascadelagen lossen scoping niet op. Als je een CSS-bestand hebt met een @layer
, zeg card.css
en je wilt alle links binnen de kaart opmaken, schrijf dan geen stijlen zoals:
a {
…
}
Dit zal ertoe leiden dat alle a
-tags in uw bestand deze overschrijving krijgen. Het is nog steeds belangrijk om uw stijlen goed te bepalen :
.card a {
…
}
Regel 2: cascadelagen worden geordend achter niet-gelaagde CSS
Het is belangrijk op te merken dat een gelaagd CSS-bestand niet-gelaagde CSS niet zal overschrijven. Dit was een opzettelijke beslissing om het gemakkelijker te maken om lagen op een verstandigere manier te introduceren om met uw bestaande codebase te werken. Het gebruik van een reset.css
bestand is bijvoorbeeld een goed startpunt en gebruiksscenario voor cascadelagen.
Regel 3: !important
keert de cascadespecificiteit om
Hoewel gelaagde stijlen in het algemeen minder specifiek zijn dan niet-gelaagde stijlen, wordt dit met !important
omgekeerd. In een laag zijn declaraties met de regel !important
specifieker dan niet-gelaagde stijlen.
In dat geval keren de !important
stijlen hun specificiteit om. Het diagram hierboven laat dit ter referentie zien: auteur @lagen hebben minder prioriteit dan auteur normaal, die minder prioriteit hebben dan auteur !belangrijk en die minder prioriteit hebben dan auteur @laag !belangrijk.
Als je meerdere lagen hebt, krijgt de eerste laag met !important
de prioriteit !important
en is deze de meest specifieke stijl.
Regel 4: Begrijp injectiepunten
Omdat de laagvolgorde wordt bepaald wanneer elke laagnaam voor het eerst in uw code verschijnt, kunt u deze negeren als u een @layer
-declaratie plaatst na het importeren en instellen layer()
's, of na een andere @layer
-instructie. Anders dan in CSS, waar de stijlregel het verst naar beneden op de pagina wordt toegepast voor cascadelagen, wordt de volgorde in eerste instantie bepaald.
Dit kan in een lijst, in een laagblok of in een import zijn. Als je @layer
na een importlijst met layer()
plaatst, zal er niets gebeuren. Als u het bovenaan het bestand plaatst, wordt de laagvolgorde ingesteld en kunt u de lagen binnen de architectuur duidelijk zien.
Regel #5: let op uw specificiteit
Met cascadelagen zal een minder specifieke selector (zoals a
) een meer specifieke selector (zoals .link
) overschrijven als die minder specifieke selector zich op een specifiekere laag bevindt. Overweeg het volgende:
a
in layer(components)
zou .pink
in layer(utilities)
overschrijven als: @layer utilities, components
waren opgegeven. Hoewel dit een opzettelijk onderdeel van de API is, kan dit verwarrend en frustrerend zijn als je het niet verwacht.
Dus als u hulpprogrammaklassen schrijft, neem deze dan altijd op als een laag van hogere orde dan de componenten waarmee u ze wilt overschrijven. Je zou kunnen denken: "Ik heb zojuist deze .pink
-klasse toegevoegd om de kleur te veranderen, maar deze wordt niet toegepast".
Meer informatie over cascadelagen
U kunt ook deze bronnen raadplegen voor meer informatie over cascadelagen: