Zalety korzystania z właściwości niestandardowych w systemach projektowania i bibliotekach komponentów.
Nazywam się Dave i pracuję jako starszy programista front-endu w firmie Nordhealth. Pracuję nad projektem i rozwojem naszego systemu projektowego Nord, który obejmuje tworzenie komponentów internetowych do naszej biblioteki komponentów. Chcę opowiedzieć, jak rozwiązaliśmy problemy związane ze stylizacją komponentów internetowych, używając właściwości niestandardowych CSS, oraz o niektórych innych zaletach korzystania z właściwości niestandardowych w systemach projektowania i bibliotekach komponentów.
Jak tworzymy komponenty sieciowe
Do tworzenia naszych komponentów internetowych używamy biblioteki Lit, która zawiera wiele gotowych fragmentów kodu, takich jak stan, ograniczone style, szablony itp. Biblioteka Lit jest nie tylko lekka, ale też oparta na natywnych interfejsach API JavaScriptu, co oznacza, że możemy dostarczyć prosty pakiet kodu, który korzysta z funkcji już dostępnych w przeglądarce.
Największą zaletą komponentów internetowych jest jednak to, że działają one z prawie każdym istniejącym frameworkiem JavaScriptu, a nawet bez frameworka. Gdy na stronie jest już wskazany główny pakiet JavaScriptu, używanie komponentu internetowego jest bardzo podobne do korzystania z elementu HTML. Jedynym prawdziwym znakiem, że nie jest to natywny element HTML, jest konsekwentne stosowanie myślnika w tagach, co jest standardem oznaczającym dla przeglądarki, że jest to komponent internetowy.
Hermetyzacja stylu w modelu shadow DOM
Podobnie jak natywne elementy HTML mają model Shadow DOM, tak samo jest w przypadku komponentów internetowych. Shadow DOM to ukryte drzewo węzłów w elemencie. Najlepszym sposobem na wizualizację tego procesu jest otwarcie narzędzia do inspekcji witryny i włączenie opcji „Pokaż drzewo Shadow DOM”. Następnie w inspektorze sprawdź element domyślnego wejścia. Teraz możesz otworzyć to wejście i zobaczyć wszystkie jego elementy. Możesz to nawet wypróbować na jednym z naszych komponentów internetowych. Spróbuj sprawdzić nasz niestandardowy komponent pola wejściowego, aby zobaczyć jego model Shadow DOM.
Jedną z zalet (lub wad, w zależności od punktu widzenia) modelu Shadow DOM jest hermetyzacja stylów. Jeśli napiszesz kod CSS w komponencie internetowym, te style nie będą mogły przenikać na stronę główną ani inne elementy. Będą całkowicie zawarte w komponencie. Ponadto kod CSS napisany dla strony głównej lub nadrzędnego komponentu internetowego nie może przenikać do Twojego komponentu internetowego.
Ta możliwość opakowania stylów jest zaletą naszej biblioteki komponentów. Dzięki temu mamy większą pewność, że gdy ktoś użyje jednego z naszych komponentów, będzie on wyglądał tak, jak chcieliśmy, niezależnie od stylów zastosowanych na stronie nadrzędnej. Aby jeszcze bardziej to ułatwić, dodaliśmy all: unset;
do katalogu głównego (czyli „hosta”) wszystkich naszych komponentów internetowych.
Co jednak, jeśli ktoś, kto używa Twojego komponentu internetowego, ma uzasadniony powód, aby zmienić niektóre style? Może jakiś fragment tekstu wymaga większego kontrastu ze względu na kontekst lub może trzeba zastosować grubszą ramkę? Jeśli żadne style nie mogą zostać zastosowane do Twojego komponentu, jak możesz odblokować te opcje stylizacji?
Dlatego do akcji wkraczają niestandardowe właściwości CSS.
Właściwości niestandardowe w CSS
Właściwości niestandardowe mają bardzo trafne nazwy. Są to właściwości CSS, które możesz nazwać i przypisać do nich dowolną wartość. Wymaga to tylko dodania 2 łączników. Po zadeklarowaniu właściwości niestandardowej możesz używać jej wartości w CSS za pomocą funkcji var()
.
Jeśli chodzi o dziedziczenie, wszystkie właściwości niestandardowe są dziedziczone zgodnie ze standardowym działaniem właściwości i wartości w CSS. Jako wartości innych właściwości można używać dowolnej właściwości niestandardowej zastosowanej do elementu nadrzędnego lub samego elementu. W przypadku naszych tokenów projektowych intensywnie korzystamy z właściwości niestandardowych, stosując je do elementu wyższego poziomu za pomocą naszego frameworku CSS. Oznacza to, że wszystkie elementy na stronie mogą korzystać z tych wartości tokenów, niezależnie od tego, czy są to komponenty internetowe, pomocnicze klasy CSS czy programista, który chce wybrać wartość z naszej listy tokenów.
Ta zdolność do dziedziczenia właściwości niestandardowych za pomocą funkcji var()
pozwala nam przeniknąć przez DOM cieniowany naszych komponentów internetowych i umożliwia deweloperom bardziej szczegółową kontrolę nad stylami komponentów.
Właściwości niestandardowe w komponencie Nord Web
Podczas tworzenia komponentów do naszego systemu projektowania bardzo starannie podchodzimy do kodu CSS. Staramy się tworzyć kod zwięzły, ale bardzo łatwy do utrzymania. Nasze tokeny projektowe są zdefiniowane jako właściwości niestandardowe w głównym interfejsie CSS w elemencie głównym.
Te wartości tokenów są następnie używane w naszych komponentach. W niektórych przypadkach zastosujemy wartość bezpośrednio w usłudze porównywania cen, ale w innych przypadkach zdefiniujemy nową kontekstową usługę spersonalizowaną i zastosujemy do niej wartość.
Utworzymy też abstrakcyjne wartości, które są specyficzne dla danego komponentu, ale nie występują w naszych tokenach, i przekształcimy je w kontekstualną właściwość niestandardową. Właściwości niestandardowe, które są kontekstowe dla komponentu, dają nam 2 kluczowe korzyści. Po pierwsze, oznacza to, że możemy bardziej „oszczędnie” korzystać z CSS, ponieważ wartość może być stosowana do wielu właściwości w komponencie.
Po drugie, ułatwia to wprowadzanie zmian w stanie komponentu i wariantach – wystarczy zmienić tylko właściwość niestandardową, aby zaktualizować wszystkie te właściwości, gdy np. stylizujesz stan najechania kursorem lub stan aktywny lub w tym przypadku wariant.
Największą zaletą jest jednak to, że gdy definiujemy te kontekstowe właściwości niestandardowe w komponencie, tworzymy dla każdego z naszych komponentów rodzaj niestandardowego interfejsu API CSS, z którego może korzystać użytkownik tego komponentu.
Poprzedni przykład pokazuje jeden z naszych komponentów internetowych z kontekstową usługą niestandardową, która została zmieniona za pomocą selektora. Efektem tego podejścia jest komponent, który zapewnia użytkownikowi wystarczającą elastyczność stylizacji, zachowując przy tym kontrolę nad większością rzeczywistych stylów. Dodatkowo my, jako deweloperzy komponentów, możemy przechwytywać style stosowane przez użytkownika. Jeśli chcemy dostosować lub rozszerzyć jedną z tych właściwości, możemy to zrobić bez konieczności zmiany kodu przez użytkownika.
Uważamy, że to podejście jest bardzo skuteczne nie tylko dla nas jako twórców komponentów systemu projektowania, ale też dla naszego zespołu programistów, który używa tych komponentów w naszych usługach.
Właściwości niestandardowe – dodatkowe informacje
W momencie pisania tego tekstu nie ujawniamy tych kontekstowych usług niestandardowych w dokumentacji, ale planujemy to zrobić, aby nasz szerszy zespół deweloperów mógł je zrozumieć i wykorzystać. Nasze komponenty są pakowane w npm za pomocą pliku manifestu, który zawiera wszystkie informacje o nich. Następnie, gdy publikujemy stronę dokumentacji, używamy pliku manifestu jako danych. Wykorzystujemy do tego Eleventy i jego funkcję Global Data. Planujemy uwzględnić te kontekstowe właściwości niestandardowe w tym pliku danych pliku manifestu.
Innym obszarem, który chcemy ulepszyć, jest sposób dziedziczenia wartości przez te kontekstowe usługi niestandardowe. Jeśli na przykład chcesz zmienić kolor 2 elementów oddzielnika, musisz je oba kierunkowo ustawić za pomocą selektorów lub zastosować właściwość niestandardową bezpośrednio na elemencie za pomocą atrybutu style. Może się to wydawać w porządku, ale lepiej byłoby, gdyby deweloper mógł zdefiniować te style w elemencie zawierającym lub nawet na poziomie katalogu głównego.
Wartość właściwości niestandardowej musisz ustawić bezpośrednio w komponencie, ponieważ definiujemy je w tym samym elemencie za pomocą selektora hosta komponentu. Globalne tokeny projektu, których używamy bezpośrednio w komponencie, są przekazywane bez zmian i nie są objęte tym problemem. Można je nawet przechwycić w elementach nadrzędnych. Jak możemy połączyć zalety obu tych rozwiązań?
Prywatne i publiczne właściwości niestandardowe
Własne właściwości prywatne zostały opracowane przez Lea Verou. Są to kontekstowe „prywatne” właściwości niestandardowe w komponencie, ale ustawione jako „publiczne” z opcją zastępczą.
Definiowanie kontekstowych usług niestandardowych w taki sposób oznacza, że nadal możemy wykonywać wszystkie czynności, które wykonywaliśmy wcześniej, np. dziedziczyć wartości globalnych tokenów i wykorzystywać wartości w kodzie komponentu. Komponent będzie też płynnie dziedziczyć nowe definicje tej usługi w sobie lub w dowolnym elemencie nadrzędnym.
Chociaż można argumentować, że ta metoda nie jest naprawdę „prywatna”, nadal uważamy, że jest to dość eleganckie rozwiązanie problemu, który nas niepokoił. Gdy tylko będzie to możliwe, rozwiążemy ten problem w naszych komponentach, aby nasz zespół programistów miał większą kontrolę nad ich używaniem, a jednocześnie nadal korzystał z dostępnych zabezpieczeń.
Mam nadzieję, że te informacje o tym, jak używamy komponentów internetowych z właściwościami niestandardowymi w CSS, były dla Ciebie przydatne. Daj nam znać, co o tym myślisz. Jeśli zdecydujesz się użyć którejś z tych metod w swojej pracy, możesz mnie znaleźć na Twitterze pod adresem @DavidDarnes. Możesz też znaleźć Nordhealth @NordhealthHQ na Twitterze, a także resztę mojego zespołu, który ciężko pracował nad stworzeniem tego systemu projektowego i wdrożeniem funkcji wymienionych w tym artykule: @Viljamis, @WickyNilliams i @eric_habich.
Baner powitalny autorstwa Dan Cristian Pădureț