Warstwy kaskadowe (@layer
reguła CSS) pojawią się w Chromium 99, Firefox 97 i Safari 15.4 Beta. Umożliwiają one bardziej szczegółową kontrolę nad plikami CSS, aby zapobiegać konfliktom związanym ze stylami. Jest to szczególnie przydatne w przypadku dużych baz kodu, systemów projektowania i zarządzania stylami innych firm w aplikacjach.
Umieszczanie warstw CSS w przejrzysty sposób zapobiega nieoczekiwanym zastąpieniom stylów i poprawia architekturę CSS.
Specyficzność CSS i kaskada
Specyficzność CSS określa, które style mają być stosowane do których elementów. Różne selektory, których możesz używać, określają specyfikę reguły stylu. Na przykład elementy są mniej szczegółowe niż klasy czy atrybuty, które z kolei są mniej szczegółowe niż identyfikatory. Jest to podstawowa część nauki CSS.
Aby zapobiec przypadkowemu zastąpieniu specyficzności, ludzie stosują konwencje nazewnictwa CSS, takie jak BEM. Nadawanie wszystkim obiektom tej samej nazwy klasy powoduje, że wszystkie obiekty są umieszczane na tym samym poziomie szczegółowości. Nie zawsze jednak można zachować taką organizację stylów, zwłaszcza podczas pracy z kodem i systemami projektowania innych firm.
Warstwy kaskadowe mają na celu rozwiązanie tego problemu. Wprowadzają nową warstwę do kaskady CSS. W przypadku stylów warstwowych pierwszeństwo warstwy zawsze wygrywa ze specyficznością selektora.
Na przykład selektor .post a.link
ma większą specyficzność niż .card a
. Jeśli spróbujesz nadać styl linkowi na karcie w poście, zostanie zastosowany bardziej szczegółowy selektor.
Dzięki użyciu @layer
możesz bardziej precyzyjnie określić specyficzność stylu każdego z nich i upewnić się, że style linku do karty zastąpią style linku do posta, nawet jeśli specyficzność może być liczbowo niższa, jeśli cała usługa porównywania cen znajduje się na tym samym poziomie. Wynika to z hierarchii ustawień. Stylizowane warstwy tworzą nowe kaskadowe „płaszczyzny”.
@layer
w działaniu
Ten przykład pokazuje możliwości warstw kaskadowych na przykładzie @layer
. Wyświetla się kilka linków: niektóre bez żadnych dodatkowych nazw klas, jeden z klasą .link
i jeden z klasą .pink
. Kod CSS dodaje następnie 3 warstwy: base
, typography
i utilities
, jak pokazano poniżej:
@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 */
}
}
Ostatecznie wszystkie linki są zielone lub różowe. Dzieje się tak, ponieważ .link
ma wyższą specyficzność na poziomie selektora niż a
, ale styl kolorów a
ma wyższą ważność niż @layer
. a { color: green }
zastępuje .link { color: blue }
, gdy reguła zielona znajduje się w warstwie po regule niebieskiej.
Pierwszeństwo warstwy ma większą wagę niż szczegółowość elementu.
porządkowanie warstw,
Warstwy możesz porządkować bezpośrednio na stronie, jak pokazano powyżej, lub u góry pliku.
Kolejność warstw jest ustalana na podstawie tego, kiedy po raz pierwszy pojawia się w kodzie nazwa każdej warstwy.
Oznacza to, że jeśli dodasz do góry pliku ten fragment kodu, wszystkie linki będą czerwone, a link z klasą .link
będzie niebieski:
@layer utilities, typography, base;
Dzieje się tak, ponieważ kolejność warstw została odwrócona, a na początku znajdują się teraz narzędzia, a na końcu podstawa. Dlatego reguły stylu w warstwie base
będą zawsze miały większą specyficzność niż reguły stylu w warstwie typografii. Linki nie będą już zielone, tylko czerwone lub niebieskie.
porządkowanie importów,
Innym sposobem korzystania z @layer
jest importowanie plików. Możesz to zrobić bezpośrednio podczas importowania stylów, używając funkcji layer()
, jak w tym przykładzie:
/* 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 */
Powyższy fragment kodu zawiera 3 poziomy: base
, layouts
i components
. Pliki normalizacji, motywy i typografii w folderze base
, plik post
w folderze layouts
oraz pliki cards
i footer
w folderze components
. Podczas importowania pliku warstwy są tworzone za pomocą funkcji warstwy. Inną metodą jest uporządkowanie warstw u góry pliku i ogłoszenie ich przed importem:
@layer base,
theme,
layouts,
components,
utilities;
Kolejność, w jakiej @import
stylów nie ma znaczenia dla kolejności warstw, ponieważ jest ona już ustalona w przypadku pierwszego wystąpienia nazwy warstwy. O jedno zmartwienie mniej. Nadal możesz przypisać zaimportowane pliki do określonych warstw, ale kolejność jest już ustalona.
Warstwy i kaskada
Wróćmy do ogólnego opisu i zobaczmy, gdzie są używane warstwy w ramach szerszej kaskady:
Kolejność obowiązywania zasad:
- Klient użytkownika (normalny – najniższy priorytet)
- Użytkownik lokalny @layer
- Użytkownik lokalny normalny
- Autor @layers
- Autor normalny
- Autor !important
- Autor @layer !important
- Użytkownik lokalny !important
- Klient użytkownika !important** (najwyższy priorytet)
Zauważysz, że style @layer !important
są odwrócone. Zamiast być mniej szczegółowe niż style bez warstw (normalne), mają wyższy priorytet. Wynika to z działania funkcji !important
w kaskadzie: przerywa ona normalną kaskadę w swój stylach i odwraca normalną specyficzność na poziomie warstwy (pierwszeństwo).
Zagnieżdżone warstwy
Warstwy mogą być też zagnieżdżone w inne warstwy. Ten przykład pochodzi z treści Miriam Suzanne na temat warstw kaskadowych:
@layer default {
p { max-width: 70ch; }
}
@layer framework {
@layer default {
p { margin-block: 0.75em; }
}
p { margin-bottom: 1em; }
}
W powyższym fragmencie kodu możesz uzyskać dostęp do framework.default
, używając .
jako wskaźnika warstwy default
zagnieżdżonej w poziomie framework
. Możesz też użyć skrótu:
@layer framework.default {
p { margin-block: 0.75em }
}
Powstałe warstwy i ich kolejność:
- domyślna
framework.default
framework
bez warstw- bez warstw
Na co zwrócić uwagę
Warstwy kaskadowe mogą być przydatne, jeśli używasz ich prawidłowo, ale mogą też powodować dodatkowe zamieszanie i nieoczekiwane wyniki. Podczas pracy z warstwami kaskadowymi należy zwrócić uwagę na te kwestie:
Zasada 1. Nie używaj elementu @layer
do określania zakresu
Warstwy kaskadowe nie rozwiązują problemu z określaniem zakresu. Jeśli masz plik CSS z elementem @layer
, np. card.css
, i chcesz nadać styl wszystkim linkom w karcie, nie pisz stylów w ten sposób:
a {
…
}
Spowoduje to zastąpienie wszystkich tagów a
w pliku. Nadal ważne jest prawidłowe określanie zakresu stylów:
.card a {
…
}
Reguła 2. Warstwy kaskadowe są uporządkowane za CSS bez warstw
Pamiętaj, że plik CSS z warstwami nie zastąpi kod CSS bez warstw. Ta decyzja była zamierzona, ponieważ ułatwia wprowadzenie warstw w bardziej sensowny sposób, aby można było pracować z dotychczasową bazą kodu. Używanie pliku reset.css
to dobry punkt wyjścia i przypadek użycia warstw kaskadowych.
Reguła 3. !important
odwraca specyficzność kaskadową
Chociaż style warstwowe są ogólnie mniej szczegółowe niż style bez warstw, użycie !important
odwraca tę zależność. W warstwie deklaracje z regułą !important
są bardziej szczegółowe niż style bez warstw.
W takim przypadku style !important
odwracają swoją specyficzność. Poniższy diagram pokazuje to na potrzeby odniesienia: autor @warstwy ma mniejszy priorytet niż autor normalny, który ma mniejszy priorytet niż autor !important, który ma mniejszy priorytet niż autor @warstwa !important.
Jeśli masz kilka warstw, pierwsza warstwa z !important
będzie miała pierwszeństwo przed !important
i będzie najbardziej szczegółowym stylem.
Reguła 4. Punkty wstrzyknięcia
Kolejność warstw jest ustalana na podstawie tego, kiedy po raz pierwszy pojawia się w kodzie nazwa każdej warstwy. Jeśli więc umieścisz deklarację @layer
po zaimportowaniu i ustawieniu layer()
lub po innym oświadczeniu @layer
, może ona zostać zignorowana. W przeciwieństwie do CSS, gdzie reguła stylu znajdująca się najdalej na dole strony jest stosowana do warstw kaskadowych, kolejność jest ustalana w pierwszej instancji.
Możesz użyć listy, bloku warstwy lub importu. Jeśli umieścisz @layer
po liście importu z layer()
, nic się nie stanie. Umieszczenie go na szczycie pliku spowoduje ustawienie kolejności warstw i ułatwi wyraźne widzenie warstw w architekturze.
Reguła 5. Uważaj na specyfikę
W przypadku warstw kaskadowych mniej szczegółowy selektor (np. a
) zastąpi bardziej szczegółowy selektor (np. .link
), jeśli ten mniej szczegółowy selektor znajduje się na bardziej szczegółowej warstwie. Weź pod uwagę następujące kwestie:
Wartość a
w elementach layer(components)
zastąpi wartość .pink
w elementach layer(utilities)
, jeśli określono wartość @layer utilities, components
. Jest to celowa część interfejsu API, ale może być myląca i frustrująca, jeśli nie spodziewasz się takiej sytuacji.
Jeśli więc piszesz klasy pomocnicze, zawsze uwzględniaj je jako warstwę wyższego rzędu niż komponenty, które zamierzasz zastąpić. Możesz pomyśleć: „Dodałem właśnie klasę .pink
, aby zmienić kolor, ale nie działa”.
Więcej informacji o warstwach kaskadowych
Aby dowiedzieć się więcej o warstwach kaskadowych, zapoznaj się też z tymi materiałami: