Niestandardowe właściwości CSS w kaskadzie

Opublikowany: 2022-03-10
Krótkie podsumowanie ↬ W tym artykule Miriam zagłębia się w specyfikację „Właściwości niestandardowe CSS dla zmiennych kaskadowych”, aby zapytać: „Dlaczego są one nazywane właściwościami niestandardowymi, jak działają w kaskadzie i co jeszcze możemy z nimi zrobić ? Przekraczając metaforę „zmiennej”, niestandardowe właściwości mogą zapewnić nowe sposoby na zrównoważenie kontekstu i izolacji we wzorcach i komponentach CSS.

W zeszłym miesiącu rozmawiałem na Twitterze o różnicy między stylami „zakresowymi” (generowanymi w procesie budowania) a „zagnieżdżonymi” stylami natywnymi dla CSS. Zapytałem, dlaczego, anegdotycznie, programiści unikają specyfiki selektorów identyfikatorów, przyjmując „style o zasięgu” generowane przez JavaScript? Keith Grant zasugerował, że różnica polega na zrównoważeniu kaskady* i dziedziczenia, tj. preferowaniu bliskości nad specyficznością. Spójrzmy.

Kaskada

Kaskada CSS opiera się na trzech czynnikach:

  1. Ważność określona przez flagę !important i pochodzenie stylu (użytkownik > autor > przeglądarka)
  2. Specyfika użytych selektorów (inline > ID > class > element)
  3. Źródło Kolejność samego kodu (najnowszy ma pierwszeństwo)

Nie ma nigdzie wzmianki o bliskości — relacji drzewa DOM między częściami selektora. Poniższe akapity będą miały kolor czerwony, mimo że #inner p opisuje bliższą relację niż #outer p w drugim akapicie:

Zobacz pióro [Cascade: Specity vs Proximity](https://codepen.io/smashingmag/pen/OexweJ/) Miriam Suzanne.

Zobacz kaskadę piór: Specyfika kontra bliskość Miriam Suzanne.
 <section> <p>This text is red</p> <div> <p>This text is also red!</p> </div> </section>
 #inner p { color: green; } #outer p { color: red; }

Oba selektory mają tę samą specyficzność, oba opisują ten sam element p i żaden z nich nie jest oznaczony jako !important — więc wynik jest oparty wyłącznie na kolejności źródłowej.

Więcej po skoku! Kontynuuj czytanie poniżej ↓

Style BEM i oscyloskopowe

Konwencje nazewnictwa, takie jak BEM („Block__Element — Modifier”), są używane w celu zapewnienia, że ​​każdy akapit ma „zakres” tylko do jednego elementu nadrzędnego, co pozwala całkowicie uniknąć kaskady. „Elementom” akapitu są przypisane unikalne klasy specyficzne dla ich kontekstu „blokowego”:

Zobacz pióro [BEM Selectors & Proximity](https://codepen.io/smashingmag/pen/qzPyeM/) Miriam Suzanne.

Zobacz Pen BEM Selectors & Proximity autorstwa Miriam Suzanne.
 <section class="outer"> <p class="outer__p">This text is red</p> <div class="inner"> <p class="inner__p">This text is green!</p> </div> </section>
 .inner__p { color: green; } .outer__p { color: red; }

Selektory te nadal mają to samo względne znaczenie, specyficzność i kolejność źródeł — ale wyniki są różne. „Zakresowe” lub „modułowe” narzędzia CSS automatyzują ten proces, przepisując dla nas nasz CSS na podstawie kodu HTML. W poniższym kodzie każdy akapit jest ograniczony do swojego bezpośredniego rodzica:

Zobacz pióro [Scoped Style Proximity](https://codepen.io/smashingmag/pen/NZaLWN/) Miriam Suzanne.

Zobacz książkę Pen Scoped Style Proximity autorstwa Miriam Suzanne.
 <section outer-scope> <p outer-scope>This text is red</p> <div outer-scope inner-scope> <p inner-scope>This text is green!</p> </div> </section>
 p[inner-scope] { color: green } p[outer-scope] { color: red; }

Dziedzictwo

Proximity nie jest częścią kaskady, ale jest częścią CSS. W tym miejscu dziedziczenie staje się ważne. Jeśli usuniemy p z naszych selektorów, każdy akapit odziedziczy kolor po swoim najbliższym przodku:

Zobacz pióro [Dziedzictwo: Specyficzność a bliskość](https://codepen.io/smashingmag/pen/mZBGyN/) Miriam Suzanne.

Zobacz „Dziedziczenie pióra: specyficzność a bliskość” Miriam Suzanne.
 #inner { color: green; } #outer { color: red; }

Ponieważ #inner i #outer opisują różne elementy, odpowiednio nasz div i section , obie właściwości kolorów są stosowane bez konfliktu. Zagnieżdżony element p nie ma określonego koloru, więc wyniki są określane przez dziedziczenie (kolor bezpośredniego elementu nadrzędnego), a nie przez kaskadę . Bliskość ma pierwszeństwo, a wartość #inner zastępuje #outer .

Ale jest problem: aby użyć dziedziczenia, stylizujemy wszystko wewnątrz naszej section i div . Chcemy celować konkretnie w kolor akapitu.

(Ponowne) wprowadzenie niestandardowych właściwości

Właściwości niestandardowe zapewniają nowe, natywne rozwiązanie dla przeglądarki; dziedziczą jak każda inna właściwość, ale nie muszą być używane tam, gdzie są zdefiniowane . Używając zwykłego CSS, bez żadnych konwencji nazewnictwa ani narzędzi do budowania, możemy stworzyć styl, który jest zarówno ukierunkowany, jak i kontekstowy, przy czym bliskość ma pierwszeństwo przed kaskadą:

Zobacz pióro [Niestandardowe rekwizyty: Specyfika a bliskość](https://codepen.io/smashingmag/pen/gNGdaO/) Miriam Suzanne.

Zobacz Pen Custom Rekwizyty: Specyfika kontra bliskość autorstwa Miriam Suzanne.
 p { color: var(--paragraph); } #inner { --paragraph: green; } #outer { --paragraph: red; }

Niestandardowa właściwość --paragraph dziedziczy podobnie jak właściwość color , ale teraz mamy kontrolę nad tym, jak i gdzie ta wartość jest stosowana. Właściwość --paragraph działa podobnie do parametru, który można przekazać do komponentu p , albo poprzez bezpośredni wybór (reguły specyficzności) lub kontekst (reguły bliskości).

Myślę, że to ujawnia potencjał niestandardowych właściwości, które często kojarzymy z funkcjami, domieszkami lub komponentami.

Niestandardowe „funkcje” i parametry

Funkcje, domieszki i komponenty są oparte na tej samej idei: kodzie wielokrotnego użytku, który można uruchamiać z różnymi parametrami wejściowymi, aby uzyskać spójne, ale konfigurowalne wyniki. Różnica polega na tym, co robią z wynikami. Zaczniemy od zmiennej gradientu w paski, a następnie możemy ją rozszerzyć na inne formy:

 html { --stripes: linear-gradient( to right, powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); }

Ta zmienna jest zdefiniowana w głównym elemencie html (można również użyć :root , ale to dodaje niepotrzebnej szczegółowości), więc nasza zmienna w paski będzie dostępna wszędzie w dokumencie. Możemy go zastosować wszędzie tam, gdzie obsługiwane są gradienty:

Zobacz pióro [Niestandardowe rekwizyty: zmienna](https://codepen.io/smashingmag/pen/NZwrrm/) Miriam Suzanne.

Zobacz pióro niestandardowe rekwizyty: zmienne autorstwa Miriam Suzanne.
 body { background-image: var(--stripes); }

Dodawanie parametrów

Funkcje są używane jak zmienne, ale definiują parametry do zmiany wyjścia. Możemy zaktualizować naszą zmienną --stripes , aby była bardziej funkcjonalna, definiując w niej pewne zmienne parametryczne. Zacznę od zamiany to right na var(--stripes-angle) , aby utworzyć parametr zmieniający kąt:

 html { --stripes: linear-gradient( var(--stripes-angle), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); }

Istnieją inne parametry, które możemy stworzyć, w zależności od tego, jakiemu celowi ma służyć funkcja. Czy powinniśmy pozwolić użytkownikom wybierać własne kolory pasków? Jeśli tak, to czy nasza funkcja akceptuje 5 różnych parametrów kolorów, czy tylko 3, które wyjdą na zewnątrz, tak jak mamy teraz? Czy chcemy również stworzyć parametry dla przestanków kolorów? Każdy dodany przez nas parametr zapewnia większą personalizację kosztem prostoty i spójności.

Nie ma uniwersalnej właściwej odpowiedzi na tę równowagę — niektóre funkcje muszą być bardziej elastyczne, a inne bardziej ugruntowane. Abstrakcje istnieją, aby zapewnić spójność i czytelność kodu, więc cofnij się o krok i zapytaj, jakie są Twoje cele. Co tak naprawdę powinno być możliwe do dostosowania i gdzie należy egzekwować spójność? W niektórych przypadkach bardziej pomocne może być posiadanie dwóch upartych funkcji niż jednej w pełni konfigurowalnej funkcji.

Aby użyć powyższej funkcji, musimy przekazać wartość parametru --stripes-angle i zastosować dane wyjściowe do właściwości wyjściowej CSS, takiej jak background-image :

 /* in addition to the code above… */ html { --stripes-angle: 75deg; background-image: var(--stripes); } 

Zobacz pióro [Niestandardowe rekwizyty: funkcja](https://codepen.io/smashingmag/pen/BgwOjj/) Miriam Suzanne.

Zobacz Pen Custom Rekwizyty: Funkcja Miriam Suzanne.

Dziedziczony kontra uniwersalny

Z przyzwyczajenia zdefiniowałem funkcję --stripes w elemencie html . Właściwości niestandardowe dziedziczą i chcę, aby moja funkcja była dostępna wszędzie, więc sensowne jest umieszczenie jej w elemencie głównym. Działa to dobrze w przypadku dziedziczenia zmiennych, takich jak --brand-color: blue , więc możemy oczekiwać, że zadziała również dla naszej „funkcji”. Ale jeśli spróbujemy ponownie użyć tej funkcji na zagnieżdżonym selektorze, to nie zadziała:

Zobacz pióro [Niestandardowe rekwizyty: Błąd dziedziczenia funkcji](https://codepen.io/smashingmag/pen/RzjRrM/) Miriam Suzanne.

Zobacz artykuł Pen Custom Rekwizyty: Błąd dziedziczenia funkcji autorstwa Miriam Suzanne.
 div { --stripes-angle: 90deg; background-image: var(--stripes); }

Nowy --stripes-angle jest całkowicie ignorowany. Okazuje się, że nie możemy polegać na dziedziczeniu funkcji, które trzeba ponownie obliczyć. Dzieje się tak, ponieważ każda wartość właściwości jest obliczana raz na element (w naszym przypadku element główny html ), a następnie obliczona wartość jest dziedziczona . Definiując naszą funkcję w katalogu głównym dokumentu, nie udostępniamy całej funkcji potomkom — tylko obliczony wynik naszej funkcji.

Ma to sens, jeśli umieścisz to w kategoriach kaskadowego parametru --stripes-angle . Jak każda dziedziczona właściwość CSS, jest dostępna dla potomków, ale nie dla przodków. Wartość ustawiona w zagnieżdżonym div nie jest dostępna dla funkcji, którą zdefiniowaliśmy w głównym przodku html . Aby stworzyć uniwersalnie dostępną funkcję, która przeliczy się na dowolnym elemencie, musimy zdefiniować ją na każdym elemencie:

Zobacz pióro [Niestandardowe rekwizyty: uniwersalna funkcja](https://codepen.io/smashingmag/pen/agLaNj/) Miriam Suzanne.

Zobacz Pen Custom Rekwizyty: Uniwersalna funkcja Miriam Suzanne.
 * { --stripes: linear-gradient( var(--stripes-angle), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); }

Uniwersalny selektor sprawia, że ​​nasza funkcja jest dostępna wszędzie, ale jeśli chcemy, możemy ją dokładniej zdefiniować. Ważną rzeczą jest to, że może ponownie obliczyć tylko tam, gdzie jest to wyraźnie zdefiniowane. Oto kilka alternatyw:

 /* make the function available to elements with a given selector */ .stripes { --stripes: /* etc… */; } /* make the function available to elements nested inside a given selector */ .stripes * { --stripes: /* etc… */; } /* make the function available to siblings following a given selector */ .stripes ~ * { --stripes: /* etc… */; } 

Zobacz pióro [Niestandardowe rekwizyty: Funkcja w zakresie](https://codepen.io/smashingmag/pen/JQMvGM/) Miriam Suzanne.

Zobacz Pen Custom Props: Scoped Function autorstwa Miriam Suzanne.

Można to rozszerzyć o dowolną logikę selektora, która nie opiera się na dziedziczeniu.

Darmowe parametry i wartości awaryjne

W powyższym przykładzie var(--stripes-angle) nie ma wartości i nie ma powrotu. W przeciwieństwie do zmiennych Sass lub JS, które muszą być zdefiniowane lub utworzone przed wywołaniem, niestandardowe właściwości CSS mogą być wywoływane bez definiowania. Tworzy to „wolną” zmienną, podobną do parametru funkcji, który może być dziedziczony z kontekstu.

Możemy ostatecznie zdefiniować zmienną w html lub :root (lub dowolnym innym przodku), aby ustawić dziedziczoną wartość, ale najpierw musimy rozważyć rozwiązanie awaryjne, jeśli nie zdefiniowano żadnej wartości. Istnieje kilka opcji, w zależności od tego, jakiego zachowania chcemy

  1. W przypadku „wymaganych” parametrów nie chcemy powrotu. W obecnej postaci funkcja nic nie zrobi, dopóki nie zostanie zdefiniowane --stripes-angle .
  2. W przypadku parametrów „opcjonalnych” możemy podać wartość zastępczą w funkcji var() . Po nazwie zmiennej dodajemy przecinek, po którym następuje wartość domyślna:
 var(--stripes-angle, 90deg)

Każda funkcja var() może mieć tylko jedną funkcję zastępczą — więc wszelkie dodatkowe przecinki będą częścią tej wartości. Dzięki temu możliwe jest dostarczanie złożonych wartości domyślnych z wewnętrznymi przecinkami:

 html { /* Computed: Hevetica, Ariel, sans-serif */ font-family: var(--sans-family, Hevetica, Ariel, sans-serif); /* Computed: 0 -1px 0 white, 0 1px 0 black */ test-shadow: var(--shadow, 0 -1px 0 white, 0 1px 0 black); }

Możemy również użyć zmiennych zagnieżdżonych, aby stworzyć własne reguły kaskadowe, nadając różne priorytety różnym wartościom:

 var(--stripes-angle, var(--global-default-angle, 90deg))
  1. Najpierw wypróbuj nasz jawny parametr ( --stripes-angle );
  2. Powrót do globalnego „domyślnego użytkownika” ( --user-default-angle ), jeśli jest dostępny;
  3. Na koniec powróć do naszego „domyślnego ustawienia fabrycznego” (90deg ).

Zobacz pióro [Niestandardowe rekwizyty: wartości zastępcze](https://codepen.io/smashingmag/pen/jjGvVm/) Miriam Suzanne.

Zobacz pióro niestandardowe rekwizyty: wartości zastępcze autorstwa Miriam Suzanne.

Ustawiając wartości zastępcze w var() zamiast jawnie definiować właściwość niestandardową, zapewniamy, że parametr nie będzie podlegać ograniczeniom specyficzności ani kaskadowym. Wszystkie parametry *-angle są „wolne”, aby można je było dziedziczyć z dowolnego kontekstu.

Awarie przeglądarki a zmienne awaryjne

Kiedy używamy zmiennych, musimy pamiętać o dwóch ścieżkach awaryjnych:

  1. Jakiej wartości powinny używać przeglądarki bez obsługi zmiennych?
  2. Jakiej wartości powinny używać przeglądarki obsługujące zmienne, gdy brakuje określonej zmiennej lub jest ona nieprawidłowa?
 p { color: blue; color: var(--paragraph); }

Podczas gdy stare przeglądarki ignorują właściwość deklaracji zmiennej i wracają do blue — nowoczesne przeglądarki będą czytać obie i używać tych drugich. Nasza var(--paragraph) może nie być zdefiniowana, ale jest poprawna i zastąpi poprzednią właściwość, więc przeglądarki z obsługą zmiennych powrócą do wartości dziedziczonej lub początkowej, tak jak przy użyciu słowa kluczowego unset .

Na początku może się to wydawać mylące, ale są ku temu dobre powody. Pierwszy jest techniczny: silniki przeglądarek obsługują nieprawidłową lub nieznaną składnię w „czasie analizy” (co dzieje się jako pierwsze), ale zmienne nie są rozwiązywane do „czasu obliczania wartości” (co dzieje się później).

  1. W czasie analizy deklaracje z nieprawidłową składnią są całkowicie ignorowane — powracając do wcześniejszych deklaracji. To jest ścieżka, którą pójdą stare przeglądarki. Nowoczesne przeglądarki obsługują składnię zmiennych, więc poprzednia deklaracja jest odrzucana.
  2. W czasie wartości wyliczanej zmienna jest kompilowana jako nieważna, ale jest już za późno — poprzednia deklaracja została już odrzucona. Zgodnie ze specyfikacją nieprawidłowe wartości zmiennych są traktowane tak samo jak unset :

Zobacz pióro [Niestandardowe rekwizyty: nieprawidłowe/nieobsługiwane vs. niezdefiniowane](https://codepen.io/smashingmag/pen/VJMGbJ/) Miriam Suzanne.

Zobacz niestandardowe rekwizyty pióra: nieważne/nieobsługiwane kontra niezdefiniowane autorstwa Miriam Suzanne.
 html { color: red; /* ignored as *invalid syntax* by all browsers */ /* - old browsers: red */ /* - new browsers: red */ color: not a valid color; color: var(not a valid variable name); /* ignored as *invalid syntax* by browsers without var support */ /* valid syntax, but invalid *values* in modern browsers */ /* - old browsers: red */ /* - new browsers: unset (black) */ --invalid-value: not a valid color value; color: var(--undefined-variable); color: var(--invalid-value); }

Jest to również dobre dla nas jako autorów, ponieważ pozwala nam bawić się bardziej złożonymi rozwiązaniami awaryjnymi dla przeglądarek obsługujących zmienne i zapewnia proste rozwiązania awaryjne dla starszych przeglądarek. Co więcej, pozwala nam to na użycie stanu null / undefined do ustawienia wymaganych parametrów. Staje się to szczególnie ważne, jeśli chcemy zmienić funkcję w mixin lub komponent.

Własność niestandardowa „Miksyny”

W Sass funkcje zwracają surowe wartości, podczas gdy domieszki zazwyczaj zwracają rzeczywisty wynik CSS z parami właściwość-wartość. Kiedy zdefiniujemy uniwersalną właściwość --stripes bez zastosowania jej do żadnego wyjścia wizualnego, wynik jest podobny do funkcji. Możemy sprawić, by zachowywał się bardziej jak mixin, poprzez uniwersalne zdefiniowanie wyjścia:

 * { --stripes: linear-gradient( var(--stripes-angle), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); background-image: var(--stripes); }

Dopóki --stripes-angle pozostaje nieprawidłowe lub niezdefiniowane, mixin nie skompiluje się i żaden background-image nie zostanie zastosowany. Jeśli ustawimy prawidłowy kąt na dowolnym elemencie, funkcja obliczy i da nam tło:

 div { --stripes-angle: 30deg; /* generates the background */ }

Niestety ta wartość parametru zostanie odziedziczona, więc obecna definicja tworzy tło na div i wszystkich potomkach . Aby to naprawić, musimy upewnić się, że wartość --stripes-angle nie dziedziczy, ustawiając ją na wartości initial (lub dowolnej nieprawidłowej wartości) na każdym elemencie. Możemy to zrobić na tym samym uniwersalnym selektorze:

Zobacz pióro [Niestandardowe rekwizyty: Mixin](https://codepen.io/smashingmag/pen/ZdXMJx/) Miriam Suzanne.

Zobacz Pen Custom Rekwizyty: Mixin autorstwa Miriam Suzanne.
 * { --stripes-angle: initial; --stripes: /* etc… */; background-image: var(--stripes); }

Bezpieczne style wbudowane

W niektórych przypadkach potrzebujemy, aby parametr był ustawiany dynamicznie z zewnątrz CSS — na podstawie danych z serwera zaplecza lub frameworka front-endu. Dzięki właściwościom niestandardowym możemy bezpiecznie definiować zmienne w naszym kodzie HTML, nie martwiąc się o zwykłe problemy ze specyficznością:

Zobacz pióro [Niestandardowe rekwizyty: Mixin + Inline Style](https://codepen.io/smashingmag/pen/qzPMPv/) Miriam Suzanne.

Zobacz Pen Custom Rekwizyty: Mixin + Inline Style autorstwa Miriam Suzanne.
 <div>...</div>

Style wbudowane mają dużą szczegółowość i są bardzo trudne do zastąpienia — ale dzięki właściwościom niestandardowym mamy inną opcję: zignoruj ​​je. Jeśli ustawimy div na background-image: none (na przykład), ta zmienna inline nie będzie miała żadnego wpływu. Idąc dalej, możemy stworzyć zmienną pośrednią:

 * { --stripes-angle: var(--stripes-angle-dynamic, initial); }

Teraz mamy możliwość zdefiniowania --stripes-angle-dynamic w kodzie HTML lub zignorowania go i ustawienia --stripes-angle bezpośrednio w naszym arkuszu stylów.

Zobacz pióro [Niestandardowe rekwizyty: Mixin + Inline / Override](https://codepen.io/smashingmag/pen/ZdXMao/) Miriam Suzanne.

Zobacz niestandardowe rekwizyty pióra: Mixin + Inline / Override autorstwa Miriam Suzanne.

Wstępnie ustawione wartości

W przypadku bardziej złożonych wartości lub typowych wzorców, które chcemy ponownie wykorzystać, możemy również udostępnić kilka gotowych zmiennych do wyboru:

 * { --tilt-down: 6deg; --tilt-up: -6deg; }

I użyj tych ustawień, zamiast bezpośrednio ustawiać wartość:

 <div>...</div> 

Zobacz pióro [Niestandardowe rekwizyty: Mixin + Presets](https://codepen.io/smashingmag/pen/LKemZm/) Miriam Suzanne.

Zobacz Pen Custom Rekwizyty: Mixin + Presets autorstwa Miriam Suzanne.

Świetnie nadaje się do tworzenia wykresów i wykresów opartych na danych dynamicznych, a nawet planowania dnia.

Zobacz Pen [wykres słupkowy w siatce CSS + zmienne](https://codepen.io/smashingmag/pen/wLrEyg/) autorstwa Miriam Suzanne.

Zobacz wykres Pen Bar w tabeli CSS + zmienne autorstwa Miriam Suzanne.

Komponenty kontekstowe

Możemy również zmienić ramkę naszego „miksera” jako „komponent”, stosując go do jawnego selektora i czyniąc parametry opcjonalnymi. Zamiast polegać na obecności lub nieobecności --stripes-angle do przełączania naszych wyników, możemy polegać na obecności lub braku selektora komponentów. To pozwala nam bezpiecznie ustawić wartości awaryjne:

Zobacz pióro [Niestandardowe rekwizyty: komponent](https://codepen.io/smashingmag/pen/QXqVmM/) Miriam Suzanne.

Zobacz Pen Custom Rekwizyty: Komponent autorstwa Miriam Suzanne.
 [data-stripes] { --stripes: linear-gradient( var(--stripes-angle, to right), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); background-image: var(--stripes); }

Umieszczając wartość zastępczą wewnątrz funkcji var() , możemy pozostawić --stripes-angle niezdefiniowane i „wolne”, aby dziedziczyć wartość spoza komponentu. Jest to świetny sposób na zaprezentowanie pewnych aspektów stylu komponentu dla danych wejściowych kontekstowych. Nawet „zakresowe” style generowane przez framework JS (lub objęte zakresem wewnątrz shadow-DOM, jak ikony SVG) mogą użyć tego podejścia do ujawnienia określonych parametrów dla wpływu z zewnątrz.

Izolowane komponenty

Jeśli nie chcemy udostępniać parametru do dziedziczenia, możemy zdefiniować zmienną z wartością domyślną:

 [data-stripes] { --stripes-angle: to right; --stripes: linear-gradient( var(--stripes-angle, to right), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); background-image: var(--stripes); }

Te komponenty również działałyby z klasą lub innym prawidłowym selektorem, ale wybrałem atrybut data- do stworzenia przestrzeni nazw dla dowolnych modyfikatorów:

 [data-stripes='vertical'] { --stripes-angle: to bottom; } [data-stripes='horizontal'] { --stripes-angle: to right; } [data-stripes='corners'] { --stripes-angle: to bottom right; } 

Zobacz pióro [Niestandardowe rekwizyty: izolowane komponenty](https://codepen.io/smashingmag/pen/agLaGX/) Miriam Suzanne.

Zobacz pióro niestandardowe rekwizyty: izolowane komponenty Miriam Suzanne.

Selektory i parametry

Często żałuję, że nie mogę użyć atrybutów danych do ustawienia zmiennej — funkcja obsługiwana przez specyfikację CSS3 attr() , ale jeszcze nie zaimplementowana w żadnej przeglądarce (zobacz kartę zasobów, aby uzyskać informacje o powiązanych problemach w każdej przeglądarce). To pozwoliłoby nam ściślej powiązać selektor z konkretnym parametrem:

 <div data-stripes="30deg">...</div> /* Part of the CSS3 spec, but not yet supported */ /* attr( , ) */ [data-stripes] { --stripes-angle: attr(data-stripes angle, to right); } <div data-stripes="30deg">...</div> /* Part of the CSS3 spec, but not yet supported */ /* attr( , ) */ [data-stripes] { --stripes-angle: attr(data-stripes angle, to right); } <div data-stripes="30deg">...</div> /* Part of the CSS3 spec, but not yet supported */ /* attr( , ) */ [data-stripes] { --stripes-angle: attr(data-stripes angle, to right); }

W międzyczasie możemy osiągnąć coś podobnego, używając atrybutu style :

Zobacz pióro [Niestandardowe rekwizyty: selektory stylu](https://codepen.io/smashingmag/pen/PrJdBG/) Miriam Suzanne.

Zobacz Pen Custom Props: Style Selectors autorstwa Miriam Suzanne.
 <div>...</div> /* The `*=` atttribute selector will match a string anywhere in the attribute */ [style*='--stripes-angle'] { /* Only define the function where we want to call it */ --stripes: linear-gradient(…); }

To podejście jest najbardziej przydatne, gdy oprócz ustawianego parametru chcemy uwzględnić inne właściwości. Na przykład ustawienie obszaru siatki może również dodać dopełnienie i tło:

 [style*='--grid-area'] { background-color: white; grid-area: var(--grid-area, auto / 1 / auto / -1); padding: 1em; }

Wniosek

Kiedy zaczynamy składać wszystkie te elementy razem, staje się jasne, że niestandardowe właściwości znacznie wykraczają poza typowe przypadki użycia zmiennych, które znamy. Jesteśmy w stanie nie tylko przechowywać wartości i określać je kaskadowo — ale możemy ich używać do manipulowania kaskadą na nowe sposoby i tworzenia inteligentniejszych komponentów bezpośrednio w CSS.

To wymaga od nas ponownego przemyślenia wielu narzędzi, na których polegaliśmy w przeszłości — od konwencji nazewnictwa, takich jak SMACSS i BEM, po style „zakresowe” i CSS-in-JS. Wiele z tych narzędzi pomaga ominąć specyfikę lub zarządzać stylami dynamicznymi w innym języku — przypadki użycia, do których możemy teraz odnieść się bezpośrednio za pomocą właściwości niestandardowych. Style dynamiczne, które często obliczaliśmy w JS, można teraz obsługiwać poprzez przekazywanie surowych danych do CSS.

Na początku te zmiany mogą być postrzegane jako „dodatkowa złożoność” — ponieważ nie jesteśmy przyzwyczajeni do oglądania logiki w CSS. I, jak w przypadku każdego kodu, nadmierna inżynieria może być prawdziwym niebezpieczeństwem. Twierdzę jednak, że w wielu przypadkach możemy wykorzystać tę moc nie do zwiększania złożoności, ale do przenoszenia złożoności z narzędzi i konwencji innych firm, z powrotem do podstawowego języka projektowania stron internetowych i (co ważniejsze) z powrotem do przeglądarka. Jeśli nasze style wymagają obliczeń, obliczenia te powinny znajdować się w naszym CSS.

Wszystkie te pomysły można posunąć znacznie dalej. Właściwości niestandardowe dopiero zaczynają być coraz szerzej stosowane, a my dopiero zaczynamy zarysować powierzchnię tego, co jest możliwe. Jestem podekscytowany, widząc, do czego to zmierza i co jeszcze ludzie wymyślą. Baw się dobrze!

Dalsza lektura

  • „Czas zacząć używać niestandardowych właściwości CSS”, Serg Hospodarets
  • „Przewodnik strategii po właściwościach niestandardowych CSS”, Michael Riethmuller