Warstwy kaskadowe (reguła CSS @layer
) pojawią się w Chromium 99, Firefox 97 i Safari w wersji 15.4 beta. Umożliwiają one dokładniejszą kontrolę nad plikami CSS, co pozwala uniknąć konfliktów związanych ze stylem. Jest to szczególnie przydatne w przypadku dużych baz kodu, systemów projektowania oraz zarządzania stylami innych firm w aplikacjach.
Przejrzyste układanie warstw CSS zapobiega nieoczekiwanym zastępowaniu stylu i promuje lepszą architekturę CSS.
Specyfikacja CSS i kaskada
Specyfikacja CSS określa, w jaki sposób CSS decyduje, które style zastosować do poszczególnych elementów. Różne selektory, których możesz używać, określają specyfikę każdej reguły stylu. Na przykład elementy są mniej szczegółowe niż klasy lub atrybuty, które z kolei są mniej szczegółowe niż identyfikatory. To podstawowy element uczenia się CSS.
Użytkownicy korzystają z konwencji nazewnictwa CSS, np. BEM, aby zapobiec przypadkowemu zastąpieniu specyfiki. Nadanie wszystkim jednej nazwy klasy oznacza, że wszystko znajduje się na tym samym poziomie specyfiki. Jednak nie zawsze da się zachować taki uporządkowany styl, zwłaszcza w przypadku pracy z zewnętrznymi systemami kodu i projektowania.
Celem tego problemu jest rozwiązanie warstw kaskadowych. Wprowadzają nową warstwę do kaskady CSS. W przypadku stylów warstwowych kolejność warstwy jest zawsze większa od szczegółowości selektora.
Na przykład selektor .post a.link
ma większą dokładność niż .card a
. Jeśli spróbujesz zmienić styl linku, wewnątrz karty zobaczysz, że zostanie zastosowany bardziej szczegółowy selektor.
Używając właściwości @layer
, możesz dokładniej określić specyfikę stylu każdego z nich i upewnić się, że style linków do kart zastępują style linków do postów, nawet jeśli ich dokładność liczbowa może być mniejsza, jeśli cały kod CSS znajdował się na tej samej płaszczyźnie. Wynika to z pierwszeństwa kaskadowego. Style warstwowe tworzą nowe „płaszczyzny” kaskadowe.
@layer
w akcji
Ten przykład pokazuje możliwości warstw kaskadowych za pomocą funkcji @layer
. Jest kilka linków – niektóre bez dodanych nazw klas, jeden z klasą .link
i jeden z klasą .pink
. CSS dodaje 3 warstwy: base
, typography
i utilities
w taki sposób:
@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ż chociaż właściwość .link
ma większą precyzję na poziomie selektora niż a
, w elemencie a
występuje styl kolorów o wyższym priorytecie (@layer
). a { color: green }
zastępuje .link { color: blue }
, gdy zielona reguła znajduje się w warstwie po niebieskiej regule.
Pierwszeństwo warstw jest ważniejsze niż specyfika elementu.
Porządkowanie warstw
Warstwy możesz uporządkować bezpośrednio na stronie (jak pokazano powyżej) lub uporządkować u góry pliku.
Kolejność warstw jest określana, gdy nazwa poszczególnych warstw pojawia się w kodzie po raz pierwszy.
Oznacza to, że jeśli na początku pliku dodasz następujące elementy, wszystkie linki będą czerwone, a link z klasą .link
– na niebiesko:
@layer utilities, typography, base;
Dzieje się tak, ponieważ kolejność warstw jest teraz odwrócona – narzędzia są na pierwszym miejscu, a na końcu na końcu. Z tego względu reguły stylu w warstwie base
będą zawsze miały większą szczegółowość niż reguły stylu na warstwie typograficznej. Nie będą już zielone i zamiast czerwonego lub niebieskiego koloru.
Porządkowanie importów
Innym sposobem korzystania z funkcji @layer
jest importowanie plików. Możesz to zrobić bezpośrednio podczas importowania stylów za pomocą 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 ma 3 warstwy: base
,layouts
i components
. Normalizacja, motyw i typografia w base
, z plikiem post
w layouts
, a plik cards
i footer
w components
. Podczas importowania pliku utworzone warstwy są tworzone przy użyciu funkcji warstwy. Możesz też umieścić warstwy u góry pliku i zadeklarować je przed importem:
@layer base,
theme,
layouts,
components,
utilities;
Teraz kolejność @import
stylów nie ma znaczenia dla kolejności warstw, ponieważ jest ona określona przy pierwszym wystąpieniu nazwy warstwy. To jedna sprawa mniej się przejmować. Nadal możesz ustawić zaimportowane pliki do określonych warstw, ale ich kolejność jest już ustalona.
Warstwy i kaskada
Cofnijmy się o krok i sprawdźmy, gdzie wykorzystywane są warstwy, jeśli ma to związek z szerszą kaskadą:
Kolejność pierwszeństwa:
- Normalny klient użytkownika (najniższy priorytet)
- Użytkownik lokalny @layer
- Użytkownik lokalny – normalny
- Autor: @layers
- Autor normalny
- Autor !important
- Autor @layer !important
- Lokalny użytkownik !important
- Klient użytkownika !important** (najwyższy priorytet)
Zauważysz tutaj odwrócone style w języku: @layer !important
. Zamiast tego są mniej szczegółowe niż style niewarstwowe (normalne), mają jednak wyższy priorytet. Wynika to z tego, jak funkcja !important
działa w kaskadzie: przerywa normalną kaskadę w arkuszach stylów i odwraca normalną specyficzność na poziomie warstwy (wcześniejszą).
Zagnieżdżone warstwy
Warstwy można też zagnieżdżać w innych warstwach. Poniższy przykład pochodzi z objaśnienia warstw kaskadowych autorstwa Miriam Suzanne:
@layer default {
p { max-width: 70ch; }
}
@layer framework {
@layer default {
p { margin-block: 0.75em; }
}
p { margin-bottom: 1em; }
}
We fragmencie kodu powyżej możesz uzyskać dostęp do narzędzia framework.default
, używając elementu .
jako oznaczenia, że warstwa default
jest zagnieżdżona w elemencie framework
. Możesz też napisać to w bardziej skróconym formacie:
@layer framework.default {
p { margin-block: 0.75em }
}
Otrzymane warstwy oraz kolejność warstw to:
- domyślnie
framework.default
framework
bez warstw- niewarstwowe
Na co zwrócić uwagę
Prawidłowo używane warstwy kaskadowe mogą być świetnym rozwiązaniem, ale mogą też powodować dodatkowe zamieszanie i nieoczekiwane rezultaty. Podczas pracy z warstwami kaskadowymi zwróć uwagę na te kwestie:
Reguła 1. Nie używaj @layer
do określania zakresu
Warstwy kaskadowe nie rozwiążą problemu z określaniem zakresu. Jeśli masz plik CSS z atrybutem @layer
, powiedz card.css
i chcesz nadać styl wszystkim linkom na karcie, nie wpisuj stylów takich jak:
a {
…
}
W rezultacie wszystkie tagi a
w pliku zostaną zastąpione. Nadal ważne jest, aby odpowiednio określać style:
.card a {
…
}
Reguła 2. Warstwy kaskadowe są uporządkowane pod niewarstwowym kodem CSS
Pamiętaj, że plik CSS wielowarstwowy nie zastępuje niewarstwowego arkusza CSS. Podjęliśmy tę decyzję, aby ułatwić wprowadzanie warstw w bardziej rozsądny sposób pracy z dotychczasową bazą kodu. Dobrym punktem wyjścia i zastosowaniem warstw kaskadowych jest na przykład użycie pliku reset.css
.
Reguła 3. !important
odwraca specyficzność kaskadową.
Chociaż style warstwowe są ogólnie mniej szczegółowe niż style niewarstwowe, użycie właściwości !important
odwraca to. Deklaracje z regułą !important
w warstwie są bardziej szczegółowe niż style niewarstwowe.
W takim przypadku style !important
odwracają uwagę. Powyższy diagram pokazuje to w celach informacyjnych: elementy @layers mają mniejsze pierwszeństwo niż zwykły autor, które mają mniejsze pierwszeństwo niż autor !important, które mają mniejsze priorytety niż autor @layer !important.
Jeśli masz wiele warstw, pierwsza warstwa z atrybutem !important
będzie miała pierwszeństwo przed stylem !important
i będzie najbardziej precyzyjnym stylem.
Reguła 4. Omówienie punktów wstrzykiwania
Kolejność warstw jest określana przy pierwszym wystąpieniu nazwy każdej warstwy w kodzie, dlatego jeśli po zaimportowaniu i ustawieniu tagów layer()
lub po innej instrukcji @layer
umieścisz deklarację @layer
, może ona zostać zignorowana. W przeciwieństwie do CSS, gdzie w przypadku warstw kaskadowych reguła stylu jest stosowana najdalej na dole strony, kolejność jest ustalana przy pierwszym wystąpieniu.
Może to być lista, blok warstw lub plik importu. Jeśli umieścisz kolumnę @layer
po liście importu z atrybutem layer()
, nie będzie ona działać. Umieszczenie go na początku pliku sprawi, że ustali on kolejność warstw i pomoże Ci wyraźnie zobaczyć warstwy w obrębie architektury.
Zasada nr 5: obserwuj swoją specyfikę
W przypadku warstw kaskadowych mniej szczegółowy selektor (np. a
) zastępuje bardziej szczegółowy selektor (np. .link
), jeśli znajduje się on w bardziej szczegółowej warstwie. Weź pod uwagę następujące kwestie:
Parametr a
w layer(components)
zastąpiłby .pink
w layer(utilities)
, jeśli: @layer utilities, components
. Jest to celowy element interfejsu API, ale jego działanie może być mylące i frustrujące.
Jeśli więc piszesz klasy narzędzi, zawsze umieszczaj je jako warstwę wyższego rzędu niż komponenty, którymi chcesz je zastąpić. Możesz pomyśleć: „Właśnie dodałem tę klasę .pink
, aby zmienić kolor, a kolor nie jest stosowany”.
Więcej informacji o warstwach kaskadowych
Więcej informacji o warstwach kaskadowych znajdziesz w tych materiałach: