Jedną z naszych ulubionych funkcji wstępnego przetwarzania danych CSS jest teraz wbudowana w języku: zagnieżdżanie reguł stylu.
Przed zagnieżdżeniem każdy selektor musiał zostać jawnie zadeklarowany, niezależnie od siebie. Powoduje to powtórzenia, masowe arkusze stylów i rozproszenie podczas tworzenia.
.nesting { color: hotpink; } .nesting > .is { color: rebeccapurple; } .nesting > .is > .awesome { color: deeppink; }
Po zagnieżdżeniu można kontynuować selektory, a powiązane z nimi reguły stylu można zgrupować.
.nesting { color: hotpink; > .is { color: rebeccapurple; > .awesome { color: deeppink; } } }
Spróbuj to zrobić w przeglądarce
Zagnieżdżanie pomaga programistom, bo ogranicza konieczność powtarzania selektorów, a jednocześnie w jednym lokowaniu reguł stylów powiązanych z powiązanymi elementami. Pozwala to również dopasować style
do docelowego kodu HTML. Jeśli z projektu został usunięty komponent .nesting
z poprzedniego przykładu, możesz usunąć całą grupę, zamiast wyszukiwać powiązane instancje selektora.
Nesting może pomóc w: – organizacji, – zmniejszaniu rozmiaru plików, – refaktoryzacji.
Zagnieżdżanie jest dostępne w Chrome 112, a także w Safari Technical Preview 162.
Pierwsze kroki z zagnieżdżaniem w CSS
W pozostałej części tego posta będziesz używać tej demonstracyjnej piaskownicy,która pomoże Ci zwizualizować wybrane opcje. W takim stanie domyślnym nic nie jest zaznaczone i wszystko jest widoczne. Wybierając różne kształty i rozmiary, możesz poćwiczyć składnię i zobaczyć, jak działa.
W piaskownicy znajdują się okręgi, trójkąty i kwadraty. Niektóre są małe, średnie lub duże. Inne są w kolorze niebieskim, różowym lub fioletowym. Wszystkie one znajdują się
w elemencie zawierającym .demo
. Poniżej znajduje się podgląd elementów HTML, na które będziesz kierować reklamy.
<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>
Przykłady zagnieżdżania
Zagnieżdżanie CSS pozwala definiować style elementu w kontekście innego selektora.
.parent {
color: blue;
.child {
color: red;
}
}
W tym przykładzie selektor klasy .child
jest umieszczony w selektorze klasy .parent
. Oznacza to, że zagnieżdżony selektor .child
będzie mieć zastosowanie tylko do elementów, które są elementami podrzędnymi elementów z klasą .parent
.
Ten przykład można też zapisać za pomocą symbolu &
, aby wyraźnie wskazać, gdzie należy umieścić klasę nadrzędną.
.parent {
color: blue;
& .child {
color: red;
}
}
Te 2 przykłady są równoważne pod względem praktycznym, a dostępne opcje staną się bardziej szczegółowe w miarę analizowania bardziej zaawansowanych przykładów w tym artykule.
Zaznaczanie kręgów
W tym przykładzie chodzi o dodanie stylów do zanikania i zamazywania tylko kręgów w wersji demonstracyjnej.
Bez zagnieżdżania obecnie CSS:
.demo .circle {
opacity: .25;
filter: blur(25px);
}
W przypadku zagnieżdżania można to zrobić na 2 sposoby:
/* & is explicitly placed in front of .circle */
.demo {
& .circle {
opacity: .25;
filter: blur(25px);
}
}
lub
/* & + " " space is added for you */
.demo {
.circle {
opacity: .25;
filter: blur(25px);
}
}
W efekcie wszystkie elementy wewnątrz .demo
z klasą .circle
są rozmyte i prawie niewidoczne:
Zaznaczanie trójkątów i kwadratów
To zadanie wymaga wybrania wielu zagnieżdżonych elementów, tzw. selektora grupy.
Obecnie bez zagnieżdżania, CSS pozwala na 2 sposoby:
.demo .triangle,
.demo .square {
opacity: .25;
filter: blur(25px);
}
lub za pomocą funkcji :is()
/* grouped with :is() */
.demo :is(.triangle, .square) {
opacity: .25;
filter: blur(25px);
}
W przypadku zagnieżdżania możesz to zrobić na 2 sposoby:
.demo {
& .triangle,
& .square {
opacity: .25;
filter: blur(25px);
}
}
lub
.demo {
.triangle, .square {
opacity: .25;
filter: blur(25px);
}
}
Wynik – wewnątrz .demo
pozostaje tylko tyle elementów: .circle
:
Wybieranie dużych trójkątów i okręgów
To zadanie wymaga selektora złożonego, w którym elementy muszą mieć obie klasy, by można było je wybrać.
Bez zagnieżdżania obecnie CSS:
.demo .lg.triangle,
.demo .lg.square {
opacity: .25;
filter: blur(25px);
}
lub
.demo .lg:is(.triangle, .circle) {
opacity: .25;
filter: blur(25px);
}
W przypadku zagnieżdżania możesz to zrobić na 2 sposoby:
.demo {
.lg.triangle,
.lg.circle {
opacity: .25;
filter: blur(25px);
}
}
lub
.demo {
.lg {
&.triangle,
&.circle {
opacity: .25;
filter: blur(25px);
}
}
}
W efekcie wszystkie duże trójkąty i okręgi są ukryte w obiekcie .demo
:
Wskazówka dotycząca selektorów złożonych i zagnieżdżania
Symbol &
jest tu Twoim znajomym, ponieważ pokazuje wprost, jak łączyć zagnieżdżone selektory. Na przykład:
.demo {
.lg {
.triangle,
.circle {
opacity: .25;
filter: blur(25px);
}
}
}
Chociaż jest to prawidłowy sposób zagnieżdżania, wyniki nie pasują do elementów, których możesz się spodziewać.
Powodem jest to, że jeśli za pomocą funkcji &
nie określisz oczekiwanego wyniku połączenia .lg.triangle,
.lg.circle
, rzeczywisty wynik będzie miał postać .lg .triangle, .lg
.circle
; selektory podrzędne.
Zaznaczam wszystkie kształty z wyjątkiem różowych.
To zadanie wymaga pseudoklasy negacji funkcjonalnej, gdzie elementy nie mogą mieć określonego selektora.
Bez zagnieżdżania obecnie CSS:
.demo :not(.pink) {
opacity: .25;
filter: blur(25px);
}
W przypadku zagnieżdżania możesz to zrobić na 2 sposoby:
.demo {
:not(.pink) {
opacity: .25;
filter: blur(25px);
}
}
lub
.demo {
& :not(.pink) {
opacity: .25;
filter: blur(25px);
}
}
W efekcie wszystkie kształty, które nie są różowe, są ukryte w obiekcie .demo
:
Precyzja i elastyczność dzięki &
Załóżmy, że chcesz kierować reklamy na wybrany kraj lub grupę odbiorców .demo
za pomocą selektora :not()
. &
jest wymagany do tych celów:
.demo {
&:not() {
...
}
}
Spowoduje to złożenie ciągu .demo
i :not()
na .demo:not()
w odróżnieniu od poprzedniego przykładu, który wymagał .demo :not()
. To przypomnienie jest bardzo ważne, gdy chcesz umieścić interakcję :hover
.
.demo {
&:hover {
/* .demo:hover */
}
:hover {
/* .demo :hover */
}
}
Więcej przykładów zagnieżdżania
Specyfikacja CSS na potrzeby zagnieżdżania zawiera więcej przykładów. Jeśli chcesz dowiedzieć się więcej o składni za pomocą przykładów, zapoznaj się z wieloma przykładami prawidłowych i nieprawidłowych.
W kilku następnych przykładach przedstawimy pokrótce funkcję zagnieżdżania CSS, która pomoże Ci poznać szeroki zakres możliwości, jakie zapewnia.
Umieszczanie @media
Przejście do innego obszaru arkusza stylów w celu znalezienia warunków zapytania o mediach, które modyfikuje selektor i jego style, może być bardzo rozpraszające. To wszystko eliminuje możliwość zagnieżdżenia warunków bezpośrednio w kontekście.
Dla wygody składni, jeśli zagnieżdżone zapytanie o media modyfikuje tylko style bieżącego kontekstu selektora, można użyć składni minimalnej.
.card {
font-size: 1rem;
@media (width >= 1024px) {
font-size: 1.25rem;
}
}
Bezpośrednie użycie atrybutu &
można też zastosować:
.card {
font-size: 1rem;
@media (width >= 1024px) {
&.large {
font-size: 1.25rem;
}
}
}
Ten przykład pokazuje rozwiniętą składnię za pomocą &
, a jednocześnie kieruje reklamy na karty .large
, aby zademonstrować działanie dodatkowych funkcji zagnieżdżania.
Dowiedz się więcej o zagnieżdżaniu reguł @rules.
Zagnieżdżanie w dowolnym miejscu
Wszystkie przykłady do tego momentu są kontynuowane lub dołączone w poprzednim kontekście. W razie potrzeby możesz całkowicie zmienić kontekst lub zmienić jego kolejność.
.card {
.featured & {
/* .featured .card */
}
}
Symbol &
reprezentuje odwołanie do obiektu selektora (a nie ciągu znaków) i można go umieścić w dowolnym miejscu w zagnieżdżonym selektorze. Można go nawet
umieścić wiele razy:
.card {
.featured & & & {
/* .featured .card .card .card */
}
}
Choć ten przykład wydaje się bezużyteczny, z pewnością przydaje się możliwość powtórzenia kontekstu selektora.
Nieprawidłowe przykłady zagnieżdżania
Jest kilka scenariuszy zagnieżdżania, które są nieprawidłowe i mogą Cię zaskoczyć, jeśli zagnieżdżasz dane w preprocesorach.
Zagnieżdżanie i łączenie
Wiele konwencji nazewnictwa klas CSS liczy na to, że zagnieżdżenie łączy lub dołącza selektory tak, jakby były to ciągi tekstowe. Ta metoda nie działa w przypadku zagnieżdżania CSS, ponieważ selektory nie są ciągami, a są odwołaniami do obiektów.
.card {
&--header {
/* is not equal to ".card--header" */
}
}
Dokładniejsze informacje znajdziesz w specyfikacji.
Przykład nieuczciwego zagnieżdżania
Zagnieżdżanie w listach selektora i polu :is()
Rozważ taki zagnieżdżony blok CSS:
.one, #two {
.three {
/* some styles */
}
}
To pierwszy przykład, który zaczyna się od listy selektorów, a następnie jest nadal zagnieżdżony. Poprzednie przykłady zakończyły się tylko listą selektora. W tym przykładzie zagnieżdżania nie ma nic nieprawidłowego, ale zawiera on potencjalnie trudny szczegół implementacji, jeśli chodzi o zagnieżdżanie list wewnątrz selektorów, zwłaszcza te, które zawierają selektor identyfikatorów.
Aby zagnieżdżenie działało, każda lista selektorów, która nie jest najbardziej zagnieżdżona, zostanie opakowana przez przeglądarkę ciągiem :is()
. To opakowanie zachowuje grupowanie listy selektora w dowolnym kontekście tworzenia treści. Efektem ubocznym tej grupy (:is(.one, #two)
) jest to, że przyjmuje specyficzność najwyższego wyniku w selektorach w nawiasie. W ten sposób :is()
zawsze działa, ale użycie składni zagnieżdżania może powodować niespodziankę, ponieważ nie jest to dokładnie to, co zostało opracowane. Podsumowano sztuczkę – zagnieżdżenie z identyfikatorami i listami selektorów może prowadzić do selektorów o bardzo dużej szczegółowości.
Aby wyraźnie podsumować ten trudny przykład, poprzedni blok zagnieżdżenia zostanie zastosowany do dokumentu w ten sposób:
:is(.one, #two) .three {
/* some styles */
}
Uważaj na zagnieżdżenie w obrębie listy selektora korzystającego z selektora identyfikatora lub naucz je ostrzegać, ponieważ tego typu zagnieżdżenie w obrębie tej listy selektora będzie bardzo dokładne.
Łączenie zagnieżdżania i deklaracji
Rozważ taki zagnieżdżony blok CSS:
.card {
color: green;
& { color: blue; }
color: red;
}
Kolor elementów .card
będzie miał wartość blue
.
Wszelkie deklaracje stylów wymieszanych są przenoszone na górę, tak jakby zostały utworzone przed zagnieżdżeniem. Więcej informacji znajdziesz w specyfikacji.
Jest kilka sposobów na obejście tego problemu. Poniżej opisujemy 3 style kolorów w polu &
, które zachowują kolejność kaskadową zgodną z oczekiwaniami autora. Kolor elementów .card
będzie czerwony.
.card {
color: green;
& { color: blue; }
& { color: red; }
}
Warto też pakować wszystkie style, które są zagnieżdżone, za pomocą atrybutu &
.
.card {
color: green;
@media (prefers-color-scheme: dark) {
color: lightgreen;
}
& {
aspect-ratio: 4/3;
}
}
Wykrywanie cech
Istnieją 2 świetne sposoby wykrywania zagnieżdżenia CSS: użyj zagnieżdżenia lub użyj @supports
do sprawdzenia możliwości analizy selektora zagnieżdżenia.
Korzystanie z zagnieżdżania:
html {
.has-nesting {
display: block;
}
.no-nesting {
display: none;
}
}
Używasz @supports
:
@supports (selector(&)) {
/* nesting parsing available */
}
Mój współpracownik Bramus ma świetny kod Codepen, który przedstawia tę strategię.
Debugowanie za pomocą Narzędzi deweloperskich w Chrome
Obecnie obsługa zagnieżdżania w Narzędziach deweloperskich jest minimalna. Obecnie style są reprezentowane w panelu Style zgodnie z oczekiwaniami, ale śledzenie zagnieżdżenia i jego pełnego kontekstu selektora nie jest jeszcze obsługiwane. Mamy plany i plany, żeby wszystko było przejrzyste i zrozumiałe.
W Chrome 113 planujemy wprowadzić dodatkową obsługę zagnieżdżania CSS. Więcej informacji już wkrótce.
Przyszłość
Zagnieżdżanie CSS jest dostępne tylko w wersji 1. W wersji 2 dodaliśmy więcej cukru składowego i potencjalnie mniej reguł do zapamiętania. Istnieje duże zapotrzebowanie na możliwości analizowania zagnieżdżenia w taki sposób, aby nie przeprowadzać żadnych ograniczeń i nie występować w trudnych momentach.
Nesting to duże ulepszenie języka CSS. Wywiera wpływ na niemal każdy aspekt architektoniczny CSS. Zanim będzie można opracować wersję 2, trzeba będzie dokładnie zrozumieć i poznać ten ogromny wpływ.
Na koniec oto wersja demonstracyjna, która wykorzystuje @scope
, zagnieżdżanie i @layer
. To takie ekscytujące!