Stylizowanie komponentów internetowych za pomocą udostępnionego arkusza stylów
Opublikowany: 2022-03-10Komponenty internetowe to niesamowita nowa funkcja sieci Web, umożliwiająca programistom definiowanie własnych niestandardowych elementów HTML. W połączeniu z przewodnikiem stylu komponenty internetowe mogą tworzyć interfejs API komponentu, który pozwala programistom przestać kopiować i wklejać fragmenty kodu i zamiast tego używać tylko elementu DOM. Używając shadow DOM, możemy zahermetyzować komponent sieciowy i nie musimy się martwić konfliktami o specyfikę z jakimkolwiek innym arkuszem stylów na stronie.
Jednak obecnie komponenty sieciowe i przewodniki po stylach wydają się być ze sobą sprzeczne. Z jednej strony przewodniki po stylu zapewniają zestaw reguł i stylów, które są globalnie stosowane na stronie i zapewniają spójność w całej witrynie. Z drugiej strony, komponenty sieciowe z shadow DOM zapobiegają przenikaniu globalnych stylów do ich enkapsulacji, zapobiegając w ten sposób wpływowi przewodnika stylów.
Dalsze czytanie na SmashingMag:
- Egzekwowanie najlepszych praktyk w systemach opartych na komponentach
- Jak korzystać z preprocesora LESS CSS w celu uzyskania inteligentniejszych arkuszy stylów
- Głębokie zanurzenie się w Adobe Edge Reflow
Jak więc te dwa elementy mogą współistnieć, skoro globalne przewodniki po stylach nadal zapewniają spójność i style, nawet komponentom sieciowym z shadow DOM? Na szczęście istnieją rozwiązania, które działają dzisiaj, i więcej rozwiązań w przyszłości, które umożliwią globalnym przewodnikom po stylach dostarczanie stylów do składników sieci Web. (W dalszej części tego artykułu będę używał terminu „komponenty sieciowe” w odniesieniu do niestandardowych elementów z shadow DOM.)
Jaki powinien być styl globalnego przewodnika po stylach w komponencie sieciowym?
Zanim omówimy, jak uzyskać globalny przewodnik po stylach do stylu komponentu internetowego, powinniśmy przedyskutować, co powinien, a czego nie powinien próbować stylizować.
Przede wszystkim, obecne najlepsze praktyki dotyczące komponentów sieciowych mówią, że komponent sieciowy, w tym jego style, powinien być hermetyzowany, aby nie był zależny od jakichkolwiek zasobów zewnętrznych do działania. Dzięki temu można go używać w dowolnym miejscu na stronie internetowej lub poza nią, nawet jeśli przewodnik po stylu nie jest dostępny.
Poniżej znajduje się prosty komponent internetowy formularza logowania, który zawiera wszystkie jego style.
<template> <style> :host { color: #333333; font: 16px Arial, sans-serif; } p { margin: 0; } p + p { margin-top: 20px; } a { color: #1f66e5; } label { display: block; margin-bottom: 5px; } input[type="text"], input[type="password"] { background-color: #eaeaea; border: 1px solid grey; border-radius: 4px; box-sizing: border-box; color: inherit; font: inherit; padding: 10px 10px; width: 100%; } input[type="submit"] { font: 16px/1.6 Arial, sans-serif; color: white; background: cornflowerblue; border: 1px solid #1f66e5; border-radius: 4px; padding: 10px 10px; width: 100%; } .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <div class="container"> <form action="#"> <p> <label for="username">User Name</label> <input type="text" name="username"> </p> <p> <label for="password">Password</label> <input type="password" name="password"> </p> <p> <input type="submit" value="Login"> </p> <p class="footnote">Not registered? <a href="#">Create an account</a></p> </form> </div> </template> <script> const doc = (document._currentScript || document.currentScript).ownerDocument; const template = doc.querySelector('#login-form-template'); customElements.define('login-form', class extends HTMLElement { constructor() { super(); const root = this.attachShadow({mode: 'closed'}); const temp = document.importNode(template.content, true); root.appendChild(temp); } }); </script>
Uwaga: przykłady kodu są napisane w specyfikacji wersji 1 dla komponentów internetowych.
Jednak pełne zamknięcie każdego komponentu internetowego nieuchronnie prowadziłoby do wielu duplikatów CSS, zwłaszcza jeśli chodzi o konfigurowanie typografii i stylizacji elementów natywnych. Jeśli programista chce użyć akapitu, tagu kotwicy lub pola wejściowego w swoim komponencie internetowym, powinien on być stylizowany tak, jak reszta witryny.
Jeśli w pełni zawrzemy wszystkie style, których potrzebuje składnik sieciowy, wówczas kod CSS stylizacji akapitów, znaczników zakotwiczenia, pól wejściowych itd. zostanie zduplikowany we wszystkich składnikach sieci Web, które ich używają. Zwiększyłoby to nie tylko koszty utrzymania, ale również doprowadziłoby do znacznie większych rozmiarów pobieranych plików dla użytkowników.
Zamiast hermetyzować wszystkie style, składniki sieci Web powinny tylko hermetyzować ich unikalne style, a następnie polegać na zestawie współdzielonych stylów do obsługi stylów dla wszystkich innych elementów. Te współdzielone style zasadniczo stałyby się rodzajem Normalize.css, którego składniki sieci Web mogłyby wykorzystać do zapewnienia, że elementy natywne są stylizowane zgodnie z przewodnikiem stylu.
W poprzednim przykładzie komponent sieciowy formularza logowania deklarował style tylko dla swoich dwóch unikalnych klas: .container
i .footnote
. Pozostałe style należałyby do wspólnego arkusza stylów i stylizowałyby akapity, znaczniki kotwic, pola wejściowe i tak dalej.
Krótko mówiąc, przewodnik po stylach nie powinien próbować stylizować komponentu WWW, ale powinien zawierać zestaw współdzielonych stylów, których mogą używać komponenty WWW w celu uzyskania spójnego wyglądu.
Jak stylizowano Shadow DOM za pomocą zewnętrznych arkuszy stylów?
Początkowa specyfikacja komponentów sieciowych (znana jako wersja 0) umożliwiała dowolnemu zewnętrznemu arkuszowi stylów przeniknięcie do shadow DOM poprzez użycie selektorów ::shadow
lub /deep/
CSS. Użycie ::shadow
i /deep/
umożliwiło Ci przeniknięcie przewodnika po stylu do shadow DOM i skonfigurowanie współdzielonych stylów, niezależnie od tego, czy komponent sieciowy tego chciał, czy nie.
/* Style all p tags inside a web components shadow DOM */ login-form::shadow p { color: red; }
Wraz z pojawieniem się najnowszej wersji specyfikacji komponentów sieciowych (znanej jako wersja 1), autorzy usunęli zdolność zewnętrznych arkuszy stylów do penetracji Shadow DOM i nie zapewnili żadnej alternatywy. Zamiast tego, filozofia zmieniła się z używania smoków do stylizowania komponentów sieciowych na używanie mostów. Innymi słowy, autorzy komponentów sieciowych powinni być odpowiedzialni za to, jakie zewnętrzne reguły stylów mogą stylizować ich komponenty, a nie być zmuszani do ich zezwalania.
Niestety, ta filozofia tak naprawdę jeszcze nie dogoniła sieci, co pozostawia nas w trudnej sytuacji. Na szczęście kilka rozwiązań dostępnych dzisiaj, a niektóre pojawią się w niedalekiej przyszłości, pozwolą współużytkowanemu arkuszowi stylów na stylizowanie komponentu internetowego.
Co możesz zrobić dzisiaj
Istnieją trzy techniki, których możesz użyć dzisiaj, które pozwolą komponentowi WWW współdzielić style: @import
, elementy niestandardowe i biblioteka komponentów WWW.
Korzystanie z @importu
Jedynym natywnym sposobem na przeniesienie arkusza stylów do komponentu internetowego jest użycie @import
. Chociaż to działa, jest to antywzór. Jednak w przypadku komponentów internetowych jest to jeszcze większy problem z wydajnością.
<template> <style> @import "styleguide.css" </style> <style> .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- rest of template DOM --> </template>
Normalnie @import
jest antywzorcem, ponieważ pobiera wszystkie arkusze stylów szeregowo, a nie równolegle, zwłaszcza jeśli są zagnieżdżone. W naszej sytuacji pobieranie pojedynczego arkusza stylów w serii nie jest pomocne, więc teoretycznie powinno być w porządku. Ale kiedy przetestowałem to w Chrome, wyniki pokazały, że użycie @import
spowodowało, że strona renderowała się do pół sekundy wolniej niż w przypadku zwykłego osadzenia stylów bezpośrednio w komponencie sieciowym.
Uwaga: Ze względu na różnice w działaniu funkcji wypełniania wielokrotnych importów HTML w porównaniu z natywnymi importami HTML, WebPagetest.org może być używany tylko w celu uzyskania wiarygodnych wyników w przeglądarkach, które natywnie obsługują importy HTML (np. Chrome).
Ostatecznie @import
jest nadal antywzorcem i może powodować problem z wydajnością komponentów webowych. Więc to nie jest świetne rozwiązanie.
Nie używaj Shadow DOM
Ponieważ problem z próbą dostarczenia współdzielonych stylów do komponentów sieciowych wynika z użycia cienia DOM, jednym ze sposobów na całkowite uniknięcie tego problemu jest nieużywanie cienia DOM.
Nie używając shadow DOM, będziesz tworzyć niestandardowe elementy zamiast komponentów sieciowych (patrz na bok poniżej), jedyną różnicą jest brak shadow DOM i scoping. Twój element będzie podlegał stylom strony, ale już dziś mamy z tym do czynienia, więc nie jest to nic, z czym nie wiemy już, jak sobie poradzić. Elementy niestandardowe są w pełni obsługiwane przez polyfill webcomponentjs, który świetnie obsługuje przeglądarki.
Największą zaletą elementów niestandardowych jest to, że możesz już dziś stworzyć z nich bibliotekę wzorów i nie musisz czekać, aż problem współdzielenia stylizacji zostanie rozwiązany. A ponieważ jedyną różnicą między komponentami internetowymi a elementami niestandardowymi jest cień DOM, zawsze możesz włączyć cień DOM w swoich niestandardowych elementach, gdy dostępne będzie rozwiązanie do współdzielenia stylów.
Jeśli zdecydujesz się utworzyć elementy niestandardowe, pamiętaj o kilku różnicach między elementami niestandardowymi a komponentami internetowymi.
Po pierwsze, ponieważ style elementu niestandardowego podlegają stylom strony i na odwrót, warto się upewnić, że selektory nie powodują żadnych konfliktów. Jeśli Twoje strony już używają przewodnika stylu, pozostaw style dla elementu niestandardowego w przewodniku stylu, a element wyprowadza oczekiwaną strukturę DOM i klas.
Pozostawiając style w przewodniku stylu, utworzysz płynną ścieżkę migracji dla swoich programistów, ponieważ mogą oni nadal korzystać z przewodnika stylu jak poprzednio, ale następnie powoli migrować do korzystania z nowego elementu niestandardowego, gdy tylko będą mogli. Gdy wszyscy używają elementu niestandardowego, możesz przenieść style, aby znajdowały się w elemencie, aby zachować je razem i umożliwić późniejszą refaktoryzację w komponentach internetowych.
Po drugie, upewnij się, że zaszyfrowałeś dowolny kod JavaScript wewnątrz natychmiast wywoływanego wyrażenia funkcji (IFFE), tak aby nie wylewać żadnych zmiennych do zakresu globalnego. Poza brakiem zakresu CSS, elementy niestandardowe nie zapewniają zakresu JavaScript.
Po trzecie, musisz użyć funkcji connectedCallback
elementu niestandardowego, aby dodać szablon DOM do elementu. Zgodnie ze specyfikacją komponentu internetowego, elementy niestandardowe nie powinny dodawać dzieci podczas funkcji konstruktora, więc musisz odroczyć dodawanie DOM do funkcji connectedCallback
.
Wreszcie element <slot>
nie działa poza domem shadow. Oznacza to, że będziesz musiał użyć innej metody, aby zapewnić programistom możliwość wstawienia swojej zawartości do elementu niestandardowego. Zwykle oznacza to po prostu samodzielne manipulowanie DOM, aby wstawić ich zawartość tam, gdzie chcesz.
Jednakże, ponieważ nie ma separacji między DOM cienia i DOM światła z elementami niestandardowymi, musisz również bardzo uważać, aby nie stylizować wstawionego modelu DOM ze względu na kaskadowe style elementów.
<!-- login-form.html --> <template> <style> login-form .container { max-width: 300px; padding: 50px; border: 1px solid grey; } login-form .footnote { text-align: center; } </style> <!-- Rest of template DOM --> </template> <script> (function() { const doc = (document._currentScript || document.currentScript).ownerDocument; const template = doc.querySelector('#login-form-template'); customElements.define('login-form', class extends HTMLElement { constructor() { super(); } // Without the shadow DOM, we have to manipulate the custom element // after it has been inserted in the DOM. connectedCallback() { const temp = document.importNode(template.content, true); this.appendChild(temp); } }); })(); </script>
<!-- index.html --> <link rel="stylesheet" href="styleguide.css"> <link rel="import" href="login-form.html"> <login-form></login-form>
Pod względem wydajności elementy niestandardowe są prawie tak szybkie, jak nieużywane komponenty sieciowe (tj. łączenie wspólnego arkusza stylów w head
i używanie tylko natywnych elementów DOM). Ze wszystkich technik, których możesz dziś użyć, ta jest zdecydowanie najszybsza.
Na bok: element niestandardowy jest nadal komponentem sieciowym dla wszystkich zamierzeń i celów. Termin „komponenty internetowe” jest używany do opisania czterech oddzielnych technologii: elementów niestandardowych, tagów szablonów, importu HTML i shadow DOM.
Niestety termin ten został użyty do opisania wszystkiego, co wykorzystuje dowolną kombinację czterech technologii. Doprowadziło to do wielu nieporozumień dotyczących tego, co ludzie mają na myśli, mówiąc „komponent sieciowy”. Tak jak odkrył Rob Dodson, uważam, że pomocne jest używanie różnych terminów, gdy mówię o niestandardowych elementach z i bez cienia DOM.
Większość programistów, z którymi rozmawiałem, ma tendencję do kojarzenia terminu „komponent sieciowy” z niestandardowym elementem, który używa shadow DOM. Na potrzeby tego artykułu stworzyłem sztuczne rozróżnienie między komponentem sieciowym a elementem niestandardowym.
Korzystanie z biblioteki komponentów sieciowych
Innym rozwiązaniem, z którego możesz skorzystać dzisiaj, jest biblioteka komponentów internetowych, takich jak Polymer, SkateJS lub X-Tag. Te biblioteki pomagają wypełnić luki w dzisiejszym wsparciu, a także mogą uprościć kod niezbędny do stworzenia komponentu internetowego. Zwykle zapewniają również dodatkowe funkcje, które ułatwiają pisanie komponentów internetowych.
Na przykład Polymer pozwala na stworzenie prostego komponentu internetowego w zaledwie kilku linijkach kodu JavaScript. Dodatkową korzyścią jest to, że Polymer zapewnia rozwiązanie do korzystania z cienia DOM i wspólnego arkusza stylów. Oznacza to, że możesz dziś tworzyć komponenty internetowe, które współdzielą style.
Aby to zrobić, utwórz to, co nazywają modułem stylów, który zawiera wszystkie współdzielone style. Może to być znacznik <style>
z wbudowanymi współdzielonymi stylami lub <link rel=“import”>
, który wskazuje na współdzielony arkusz stylów. W obu przypadkach uwzględnij style w komponencie internetowym za pomocą tagu <style include>
, a następnie Polymer przeanalizuje style i doda je jako wbudowany tag <style>
do komponentu internetowego.
<!-- shared-styles.html --> <dom-module> <!-- Link to a shared style sheet --> <!-- <link rel="import" href="styleguide.css"> --> <!-- Inline the shared styles --> <template> <style> :host { color: #333333; font: 16px Arial, sans-serif; } /* Rest of shared CSS */ </style> </template> </dom-module>
<!-- login-form.html --> <link rel="import" href="../polymer/polymer.html"> <link rel="import" href="../shared-styles/shared-styles.html"> <dom-module> <template> <!-- Include the shared styles --> <style include="shared-styles"></style> <style> .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- Rest of template DOM --> </template> <script> Polymer({ is: 'login-form' }); </script> </dom-module>
Jedynym minusem korzystania z biblioteki jest to, że może opóźnić czas renderowania komponentów internetowych. Nie powinno to dziwić, ponieważ pobranie kodu biblioteki i przetworzenie go zajmuje trochę czasu. Żadne składniki internetowe na stronie nie mogą rozpocząć renderowania, dopóki biblioteka nie zakończy przetwarzania.
W przypadku Polymera może opóźnić czas renderowania strony nawet o pół sekundy w porównaniu z natywnymi komponentami internetowymi. Moduł stylów, który osadza style, jest nieco wolniejszy niż moduł stylów, który łączy style, a osadzanie stylów bezpośrednio w komponencie internetowym jest tak samo szybkie, jak użycie modułu stylów.
Ponownie, Polymer nie robi nic w szczególności, aby spowolnić czas renderowania. Pobieranie biblioteki Polymer i przetwarzanie wszystkich jej niesamowitych funkcji, a także tworzenie wszystkich powiązań szablonów, zajmuje trochę czasu. To tylko kompromis, który musisz zrobić, aby korzystać z biblioteki komponentów internetowych.
Wyniki testów wydajności pokazują, że przy użyciu polimeru komponenty sieciowe będą renderować się do pół sekundy wolniej niż natywne komponenty sieciowe.
Obietnica przyszłości
Jeśli żadne z obecnych rozwiązań nie działa dla Ciebie, nie rozpaczaj. Jeśli wszystko pójdzie dobrze, w ciągu kilku miesięcy do kilku lat będziemy mogli korzystać ze wspólnych stylów przy użyciu kilku różnych podejść.
Właściwości niestandardowe
Właściwości niestandardowe (lub zmienne CSS, jak je nazywano) to sposób na ustawianie i używanie zmiennych w CSS. To pojęcie nie jest nowe w preprocesorach CSS, ale jako natywna funkcja CSS, niestandardowe właściwości są w rzeczywistości potężniejsze niż zmienna preprocesora.
Aby zadeklarować właściwość niestandardową, użyj notacji właściwości niestandardowej –my-variable: value
i uzyskaj dostęp do zmiennej za pomocą property: var(–my-variable)
. Własność niestandardowa działa kaskadowo jak każda inna reguła CSS, więc jej wartość dziedziczy po swoim rodzicu i może zostać nadpisana. Jedynym zastrzeżeniem dotyczącym właściwości niestandardowych jest to, że muszą być zadeklarowane wewnątrz selektora i nie mogą być deklarowane samodzielnie, w przeciwieństwie do zmiennej preprocesora.
<style> /* Declare the custom property */ html { --main-bg-color: red; } /* Use the custom property */ input { background: var(--main-bg-color); } </style>
Jedną z rzeczy, która sprawia, że niestandardowe właściwości są tak potężne, jest ich zdolność do przebijania cieni DOM. To nie jest ten sam pomysł, co selektory /deep/
i ::shadow
, ponieważ nie wdzierają się na siłę do komponentu sieciowego. Zamiast tego autor komponentu internetowego musi użyć właściwości niestandardowej w swoim CSS, aby można było ją zastosować. Oznacza to, że autor komponentu WWW może utworzyć interfejs API właściwości niestandardowych, którego użytkownicy komponentu WWW mogą używać do stosowania własnych stylów.
<template> <style> /* Declare the custom property API */ :host { --main-bg-color: brown; } .one { color: var(--main-bg-color); } </style> <div class="one">Hello World</div> </template> <script> /* Code to set up my-element web component */ </script> <my-element></my-element> <style> /* Override the custom variable with own value */ my-element { --main-bg-color: red; } </style>
Obsługa przez przeglądarkę właściwości niestandardowych jest zaskakująco dobra. Jedynym powodem, dla którego nie jest to rozwiązanie, z którego można korzystać dzisiaj, jest to, że nie ma działającego wypełnienia bez elementów niestandardowych w wersji 1. Zespół odpowiedzialny za webcomponentjs polyfill pracuje obecnie nad jego dodaniem, ale nie został jeszcze wydany i jest w stanie zbudowanym, co oznacza, że jeśli haszujesz swoje aktywa do produkcji, nie możesz ich użyć. Z tego co rozumiem, ma się ukazać na początku przyszłego roku.
Mimo to właściwości niestandardowe nie są dobrą metodą udostępniania stylów między składnikami sieciowymi. Ponieważ można ich używać tylko do deklarowania wartości jednej właściwości, składnik sieciowy nadal musiałby osadzić wszystkie style przewodnika stylów, aczkolwiek z ich wartościami zastąpionymi zmiennymi.
Właściwości niestandardowe są bardziej dopasowane do opcji tematycznych niż wspólnych stylów. Z tego powodu niestandardowe właściwości nie są realnym rozwiązaniem naszego problemu.
/* Użyj niestandardowej właściwości */ input { background: var(–main-bg-color); } </style>
Jedną z rzeczy, która sprawia, że niestandardowe właściwości są tak potężne, jest ich zdolność do przebijania cieni DOM. To nie jest ten sam pomysł, co selektory /deep/
i ::shadow
, ponieważ nie wdzierają się na siłę do komponentu sieciowego. Zamiast tego autor komponentu internetowego musi użyć właściwości niestandardowej w swoim CSS, aby można było ją zastosować. Oznacza to, że autor komponentu WWW może utworzyć interfejs API właściwości niestandardowych, którego użytkownicy komponentu WWW mogą używać do stosowania własnych stylów.
<template> <style> /* Declare the custom property API */ :host { --main-bg-color: brown; } .one { color: var(--main-bg-color); } </style> <div class="one">Hello World</div> </template> <script> /* Code to set up my-element web component */ </script> <my-element></my-element> <style> /* Override the custom variable with own value */ my-element { --main-bg-color: red; } </style>
Obsługa przez przeglądarkę właściwości niestandardowych jest zaskakująco dobra. Jedynym powodem, dla którego nie jest to rozwiązanie, z którego można korzystać dzisiaj, jest to, że nie ma działającego wypełnienia bez elementów niestandardowych w wersji 1. Zespół odpowiedzialny za webcomponentjs polyfill pracuje obecnie nad jego dodaniem, ale nie został jeszcze wydany i jest w stanie zbudowanym, co oznacza, że jeśli haszujesz swoje aktywa do produkcji, nie możesz ich użyć. Z tego co rozumiem, ma się ukazać na początku przyszłego roku.
Mimo to właściwości niestandardowe nie są dobrą metodą udostępniania stylów między składnikami sieciowymi. Ponieważ można ich używać tylko do deklarowania wartości jednej właściwości, składnik sieciowy nadal musiałby osadzić wszystkie style przewodnika stylów, aczkolwiek z ich wartościami zastąpionymi zmiennymi.
Właściwości niestandardowe są bardziej dopasowane do opcji tematycznych niż wspólnych stylów. Z tego powodu niestandardowe właściwości nie są realnym rozwiązaniem naszego problemu.
@Zastosuj Zasady
Oprócz właściwości niestandardowych CSS otrzymuje również reguły @apply
. Zastosuj reguły są zasadniczo domieszkami dla świata CSS. Są one deklarowane w podobny sposób do właściwości niestandardowych, ale można ich używać do deklarowania grup właściwości, a nie tylko wartości właściwości. Podobnie jak w przypadku właściwości niestandardowych, ich wartości mogą być dziedziczone i zastępowane i muszą być zadeklarowane wewnątrz selektora, aby działały.
<style> /* Declare rule */ html { --typography: { font: 16px Arial, sans-serif; color: #333333; } } /* Use rule */ input { @apply --typography; } </style>
Obsługa reguł @apply
przez przeglądarkę w zasadzie nie istnieje. Chrome obecnie obsługuje to za flagą funkcji (której nie mogłem znaleźć), ale to wszystko. Nie ma również działającego wypełnienia z tego samego powodu, z którego nie ma wypełnienia dla właściwości niestandardowych. Zespół webcomponentjs polyfill pracuje również nad dodaniem reguł @apply
wraz z właściwościami niestandardowymi, więc obie będą dostępne po wydaniu nowej wersji.
W przeciwieństwie do właściwości niestandardowych, reguły @apply
są znacznie lepszym rozwiązaniem do udostępniania stylów. Ponieważ mogą skonfigurować grupę deklaracji właściwości, można ich użyć do ustawienia domyślnych stylów dla wszystkich elementów natywnych, a następnie użyć ich w komponencie WWW. Aby to zrobić, musiałbyś utworzyć regułę @apply
dla każdego elementu natywnego.
Jednak, aby wykorzystać style, musiałbyś zastosować je ręcznie do każdego elementu natywnego, co nadal powielałoby deklarację stylu w każdym komponencie WWW. Chociaż jest to lepsze niż osadzanie wszystkich stylów, nie jest to zbyt wygodne, ponieważ staje się szablonem na górze każdego komponentu internetowego, o którym trzeba pamiętać, aby dodać, aby style działały poprawnie.
/* styleguide.css */ html { --typography: { color: #333333; font: 16px Arial, sans-serif; } --paragraph: { margin: 0; } --label { display: block; margin-bottom: 5px; } --input-text { background-color: #eaeaea; border: 1px solid grey; border-radius: 4px; box-sizing: border-box; color: inherit; font: inherit; padding: 10px 10px; width: 100%; } --input-submit { font: 16px/1.6 Arial, sans-serif; color: white; background: cornflowerblue; border: 1px solid #1f66e5; border-radius: 4px; padding: 10px 10px; width: 100%; } /* And so on for every native element */ }
<!-- login-form.html --> <template> <style> :host { @apply --typography; } p { @apply --paragraph; } label { @apply --label; } input-text { @apply --input-text; } .input-submit { @apply --input-submit; } .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- Rest of template DOM --> </template>
Ze względu na potrzebę rozbudowanego szablonu nie sądzę, aby reguły @apply
były dobrym rozwiązaniem do współdzielenia stylów pomiędzy komponentami webowymi. Są jednak świetnym rozwiązaniem do motywowania.
w cieniu DOM
Zgodnie ze specyfikacją komponentu internetowego, przeglądarki ignorują wszelkie <link rel=“stylesheet”>
w shadow DOM, traktując je tak samo, jak wewnątrz fragmentu dokumentu. Uniemożliwiło nam to łączenie się w dowolnych współdzielonych stylach w naszych komponentach sieciowych, co było niefortunne — to znaczy jeszcze kilka miesięcy temu, kiedy Grupa Robocza Komponentów Sieciowych zaproponowała, aby tagi <link rel=“stylesheet”>
działały w cień DOM. Po zaledwie tygodniu dyskusji wszyscy zgodzili się, że powinni, a kilka dni później dodali to do specyfikacji HTML.
<template> <link rel="stylesheet" href="styleguide.css"> <style> .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- rest of template DOM --> </template>
Jeśli wydaje się to trochę zbyt szybkie, aby grupa robocza zgodziła się na specyfikację, to dlatego, że nie była to nowa propozycja. Sprawienie, by tagi link
działały w cieniu DOM, zostało faktycznie zaproponowane co najmniej trzy lata temu, ale było to opóźnione, dopóki nie mogli upewnić się, że nie stanowi to problemu dla wydajności.
Jeśli akceptacja propozycji nie jest wystarczająco ekscytująca, Chrome 55 (obecnie Chrome Canary) dodał początkową funkcjonalność umożliwiającą działanie tagów link
w cieniu DOM. Wydaje się nawet, że ta funkcjonalność wylądowała w obecnej wersji Chrome. Nawet Safari zaimplementowało tę funkcję w Safari 18.
Możliwość łączenia we współdzielonych stylach jest zdecydowanie najwygodniejszą metodą współdzielenia stylów między komponentami internetowymi. Wszystko, co musisz zrobić, to utworzyć tag link
, a wszystkie elementy natywne będą odpowiednio stylizowane, bez dodatkowej pracy.
Oczywiście sposób, w jaki twórcy przeglądarek zaimplementują tę funkcję, określi, czy to rozwiązanie jest opłacalne. Aby to działało poprawnie, tagi link
musiałyby zostać zdeduplikowane, tak aby wiele komponentów internetowych żądających tego samego pliku CSS powodowało tylko jedno żądanie HTTP. CSS również musiałby zostać przeanalizowany tylko raz, tak aby każda instancja komponentu internetowego nie musiała ponownie obliczać wspólnych stylów, ale zamiast tego ponownie wykorzystywała obliczone style.
Chrome robi już obie te rzeczy. Tak więc, jeśli wszyscy inni twórcy przeglądarek zaimplementują to w ten sam sposób, tagi link
działające w cieniu DOM z pewnością rozwiążą kwestię udostępniania stylów między komponentami sieciowymi.
Konstruowalne arkusze stylów
Być może trudno w to uwierzyć, ponieważ jeszcze go nie mamy, ale tag link
działający w cieniu DOM nie jest rozwiązaniem długoterminowym. Zamiast tego jest to tylko krótkoterminowe rozwiązanie, które prowadzi nas do prawdziwego rozwiązania: możliwych do zbudowania arkuszy stylów.
Konstruowalne arkusze stylów to propozycja umożliwiająca tworzenie obiektów StyleSheet
w JavaScript za pomocą funkcji konstruktora. Skonstruowany arkusz stylów mógłby następnie zostać dodany do shadow DOM poprzez API, co pozwoliłoby shadow DOM na użycie zestawu współdzielonych stylów.
Niestety to wszystko, co udało mi się wyciągnąć z propozycji. Próbowałem dowiedzieć się więcej o tym, czym są arkusze stylów, które można zbudować, pytając Grupę Roboczą Komponentów Sieciowych, ale przekierowali mnie na listę dyskusyjną Grupy Roboczej CSS W3C, gdzie zapytałem ponownie, ale nikt nie odpowiedział. Nie mogłem nawet zrozumieć, jak postępuje propozycja, ponieważ nie była aktualizowana od ponad dwóch lat.
Mimo to Grupa Robocza Komponentów Sieciowych używa go jako rozwiązania do współdzielenia stylów pomiędzy komponentami sieciowymi. Miejmy nadzieję, że albo propozycja zostanie zaktualizowana, albo grupa robocza Web Components opublikuje więcej informacji na jej temat i jego przyjęcie. Do tego czasu wydaje się, że rozwiązanie „długoterminowe” nie nastąpi w dającej się przewidzieć przyszłości.
Zdobyta wiedza
Po miesiącach badań i testów mam nadzieję na przyszłość. Pocieszająca jest świadomość, że po latach braku rozwiązania do współdzielenia stylów między komponentami sieciowymi, wreszcie są odpowiedzi. Te odpowiedzi mogą nie być ustalone jeszcze przez kilka lat, ale przynajmniej są.
Jeśli chcesz dziś używać współdzielonego przewodnika stylów do tworzenia stylów komponentów internetowych, albo nie możesz użyć cieniowanego modelu DOM i zamiast tego tworzyć elementy niestandardowe, albo możesz użyć biblioteki komponentów internetowych, która obsługuje wielowypełnienia w celu udostępniania stylów. Oba rozwiązania mają swoje wady i zalety, więc używaj tego, co najlepiej pasuje do Twojego projektu.
Jeśli zdecydujesz się trochę poczekać, zanim zagłębisz się w komponenty webowe, to za kilka lat powinniśmy mieć kilka świetnych rozwiązań do dzielenia się stylami między nimi. Sprawdzaj więc, jak się rozwija.
Rzeczy, o których należy pamiętać
Pamiętaj o kilku rzeczach, jeśli już dziś zdecydujesz się na użycie niestandardowych elementów lub komponentów internetowych.
Co najważniejsze, specyfikacja komponentów sieciowych jest wciąż aktywnie rozwijana, co oznacza, że wszystko może się zmienić i będzie się zmieniać. Komponenty sieci nadal są bardzo krwawiące, więc bądź przygotowany na to, aby pozostać na palcach, gdy będziesz się z nimi rozwijać.
Jeśli zdecydujesz się na użycie shadow DOM, wiedz, że jest on dość powolny i nieefektywny w przeglądarkach z wielokrotnym wypełnieniem. Z tego powodu programiści Polymer stworzyli swoją podejrzaną implementację DOM i uczynili ją domyślną.
Chrome, Opera i ostatnio Safari to jedyne przeglądarki obsługujące shadow DOM w wersji 0. Firefox jest wciąż w fazie rozwoju, chociaż wspiera go w ramach eksperymentu od wersji 29. Microsoft wciąż rozważa go dla Edge i ma go jako wysoki priorytet na swojej mapie drogowej.
Jednak shadow DOM w wersji 0 to stara specyfikacja. Shadow DOM w wersji 1 jest nowym i tylko Chrome, Safari i Opera w pełni go obsługują. Nie wspominając o tym, że elementy niestandardowe w wersji 0 przeszły tę samą aktualizację i tylko Chrome w pełni obsługuje elementy niestandardowe w wersji 1, podczas gdy podgląd techniczny Safari obsługuje je od wersji 17. Elementy niestandardowe w wersji 1 mają kilka poważnych zmian w sposobie pisania komponentów internetowych, więc upewnij się, że w pełni rozumiesz, co to oznacza.
Wreszcie, wypełnienie webcomponentjs obsługuje tylko implementację w wersji 0 cienia DOM i elementów niestandardowych. Gałąź wypełnienia w wersji 1 będzie obsługiwać wersję 1, ale nie została jeszcze wydana.