Stilarea componentelor web utilizând o foaie de stil partajată
Publicat: 2022-03-10Componentele web sunt o nouă caracteristică uimitoare a web-ului, permițând dezvoltatorilor să-și definească propriile elemente HTML personalizate. Atunci când sunt combinate cu un ghid de stil, componentele web pot crea un API component, care le permite dezvoltatorilor să nu mai copieze și să lipească fragmente de cod și să folosească în schimb doar un element DOM. Folosind shadow DOM, putem încapsula componenta web și nu trebuie să ne facem griji cu privire la războaiele de specificitate cu orice altă foaie de stil de pe pagină.
Cu toate acestea, componentele web și ghidurile de stil par în prezent să fie în dezacord unele cu altele. Pe de o parte, ghidurile de stil oferă un set de reguli și stiluri care sunt aplicate la nivel global paginii și asigură coerența pe site. Pe de altă parte, componentele web cu umbră DOM împiedică orice stiluri globale să pătrundă în încapsularea lor, împiedicând astfel ghidul de stil să le afecteze.
Citiți suplimentare despre SmashingMag:
- Aplicarea celor mai bune practici în sistemele bazate pe componente
- Cum să utilizați preprocesorul LESS CSS pentru foi de stil mai inteligente
- O scufundare profundă în Adobe Edge Reflow
Deci, cum pot coexista cele două, cu ghidurile de stil globale care continuă să ofere consistență și stiluri, chiar și componentelor web cu DOM-ul umbră? Din fericire, există soluții care funcționează astăzi și mai multe soluții care vor veni, care permit ghidurilor de stil globale să ofere stil componentelor web. (Pentru restul acestui articol, voi folosi termenul „componente web” pentru a face referire la elemente personalizate cu DOM-ul umbră.)
Ce ar trebui să ghideze un stil global într-o componentă web?
Înainte de a discuta despre cum să obțineți un ghid de stil global pentru a stila o componentă web, ar trebui să discutăm ce ar trebui și nu ar trebui să încercăm să stilăm.
În primul rând, cele mai bune practici actuale pentru componentele web afirmă că o componentă web, inclusiv stilurile sale, ar trebui să fie încapsulată, astfel încât să nu depindă de resurse externe pentru a funcționa. Acest lucru îi permite să fie folosit oriunde pe sau în afara site-ului web, chiar și atunci când ghidul de stil nu este disponibil.
Mai jos este o componentă web simplă a formularului de conectare care încapsulează toate stilurile sale.
<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>
Notă: Exemplele de cod sunt scrise în specificația versiunii 1 pentru componentele web.
Cu toate acestea, încapsularea completă a fiecărei componente web ar duce inevitabil la o mulțime de CSS duplicat, mai ales când vine vorba de configurarea tipografiei și stilului elementelor native. Dacă un dezvoltator dorește să folosească un paragraf, o etichetă de ancorare sau un câmp de intrare în componenta sa web, ar trebui să fie stilat ca restul site-ului.
Dacă încapsulăm pe deplin toate stilurile de care are nevoie componenta web, atunci CSS-ul pentru stilul paragrafelor, etichetele de ancorare, câmpurile de intrare și așa mai departe ar fi duplicat în toate componentele web care le folosesc. Acest lucru nu numai că ar crește costurile de întreținere, dar ar duce și la dimensiuni mult mai mari de descărcare pentru utilizatori.
În loc să încapsuleze toate stilurile, componentele web ar trebui să încapsuleze doar stilurile lor unice și apoi să depindă de un set de stiluri partajate pentru a gestiona stilurile pentru orice altceva. Aceste stiluri partajate ar deveni în esență un fel de Normalize.css, pe care componentele web l-ar putea folosi pentru a se asigura că elementele native sunt stilate conform ghidului de stil.
În exemplul anterior, componenta web a formularului de autentificare ar declara stilurile doar pentru cele două clase unice ale sale: .container
și .footnote
. Restul stilurilor ar aparține în foaia de stil partajată și ar stila paragrafele, etichetele de ancorare, câmpurile de intrare și așa mai departe.
Pe scurt, ghidul de stil nu ar trebui să încerce să stileze componenta web, ci ar trebui să ofere un set de stiluri partajate pe care componentele web le pot folosi pentru a obține un aspect consistent.
Cum se facea stilizarea Shadow DOM cu foi de stil externe
Specificația inițială pentru componentele web (cunoscută ca versiunea 0) a permis oricărei foi de stil externe să pătrundă în DOM-ul umbră prin utilizarea selectoarelor ::shadow
sau /deep/
CSS. Utilizarea ::shadow
și /deep/
v-a permis să aveți un ghid de stil să pătrundă în DOM-ul umbră și să configurați stilurile partajate, indiferent dacă componenta web a dorit sau nu.
/* Style all p tags inside a web components shadow DOM */ login-form::shadow p { color: red; }
Odată cu apariția celei mai noi versiuni a specificației componentelor web (cunoscută ca versiunea 1), autorii au eliminat capacitatea foilor de stil externe de a pătrunde în DOM-ul umbră și nu au oferit nicio alternativă. În schimb, filosofia s-a schimbat de la folosirea dragonilor pentru a stila componentele web la utilizarea podurilor. Cu alte cuvinte, autorii componentelor web ar trebui să fie responsabili de ce reguli de stil externe au voie să stileze componenta lor, mai degrabă decât să fie forțați să le permită.
Din păcate, această filozofie nu a ajuns încă din urmă cu web-ul, ceea ce ne lasă într-un pic de murătură. Din fericire, câteva soluții disponibile astăzi și unele care vor veni într-un viitor nu atât de îndepărtat, vor permite unei foi de stil partajate să stileze o componentă web.
Ce poți face astăzi
Există trei tehnici pe care le puteți folosi astăzi și care vor permite unei componente web să partajeze stiluri: @import
, elemente personalizate și o bibliotecă de componente web.
Folosind @import
Singura modalitate nativă astăzi de a aduce o foaie de stil într-o componentă web este utilizarea @import
. Deși funcționează, este un anti-model. Pentru componentele web, totuși, este o problemă de performanță și mai mare.
<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>
În mod normal, @import
este un anti-model deoarece descarcă toate foile de stil în serie, în loc să fie în paralel, mai ales dacă sunt imbricate. În situația noastră, descărcarea unei singure foi de stil în serie nu poate fi ajutată, așa că în teorie ar trebui să fie bine. Dar când am testat acest lucru în Chrome, rezultatele au arătat că utilizarea @import
a făcut ca pagina să fie redată cu până la jumătate de secundă mai lent decât atunci când doar încorporam stilurile direct în componenta web.
Notă: Din cauza diferențelor în modul în care funcționează polyfill-ul importurilor HTML în comparație cu importurile native HTML, WebPagetest.org poate fi folosit doar pentru a oferi rezultate fiabile în browserele care acceptă nativ importurile HTML (de exemplu, Chrome).
În cele din urmă, @import
este încă un anti-model și poate fi o problemă de performanță în componentele web. Deci, nu este o soluție grozavă.
Nu utilizați Shadow DOM
Deoarece problema încercării de a oferi stiluri partajate componentelor web provine din utilizarea DOM-ului umbră, o modalitate de a evita în întregime problema este să nu utilizați DOM-ul umbră.
Dacă nu utilizați shadow DOM, veți crea elemente personalizate în loc de componente web (vezi partea de mai jos), singura diferență fiind lipsa shadow DOM și a domeniului. Elementul dvs. va fi supus stilurilor paginii, dar deja trebuie să ne ocupăm de asta astăzi, așa că nu este nimic pe care să nu știm deja să gestionăm. Elementele personalizate sunt pe deplin acceptate de polifill-ul webcomponentjs, care are un suport excelent pentru browser.
Cel mai mare beneficiu al elementelor personalizate este că puteți crea o bibliotecă de modele folosindu-le astăzi și nu trebuie să așteptați până când problema stilului partajat este rezolvată. Și pentru că singura diferență dintre componentele web și elementele personalizate este DOM-ul umbră, puteți oricând să activați DOM-ul umbră în elementele dvs. personalizate odată ce este disponibilă o soluție pentru stilul partajat.
Dacă decideți să creați elemente personalizate, fiți conștienți de câteva diferențe dintre elementele personalizate și componentele web.
În primul rând, deoarece stilurile pentru elementul personalizat sunt supuse stilurilor de pagină și invers, trebuie să vă asigurați că selectatorii dvs. nu provoacă conflicte. Dacă paginile dvs. folosesc deja un ghid de stil, lăsați stilurile pentru elementul personalizat în ghidul de stil și lăsați elementul să scoată DOM și structura de clasă așteptată.
Lăsând stilurile în ghidul de stil, veți crea o cale de migrare fluidă pentru dezvoltatorii dvs., deoarece aceștia pot continua să folosească ghidul de stil ca înainte, dar apoi pot migra încet la utilizarea noului element personalizat atunci când sunt capabili. Odată ce toată lumea folosește elementul personalizat, puteți muta stilurile pentru a se afla în interiorul elementului pentru a le menține împreună și pentru a permite o refactorizare mai ușoară a componentelor web mai târziu.
În al doilea rând, asigurați-vă că încapsulați orice cod JavaScript într-o expresie de funcție invocată imediat (IFFE), astfel încât să nu eliminați nicio variabilă în domeniul global. Pe lângă faptul că nu furnizează domeniul CSS, elementele personalizate nu oferă domeniul JavaScript.
În al treilea rând, va trebui să utilizați funcția connectedCallback
a elementului personalizat pentru a adăuga șablonul DOM la element. Conform specificației componentei web, elementele personalizate nu ar trebui să adauge copii în timpul funcției de constructor, așa că va trebui să amânați adăugarea DOM-ului la funcția connectedCallback
.
În cele din urmă, elementul <slot>
nu funcționează în afara DOM-ului umbră. Aceasta înseamnă că va trebui să utilizați o metodă diferită pentru a oferi dezvoltatorilor o modalitate de a-și introduce conținutul în elementul personalizat. De obicei, acest lucru implică doar manipularea DOM-ului pentru a-i introduce conținutul acolo unde doriți.
Cu toate acestea, deoarece nu există nicio separare între DOM-ul umbră și DOM-ul ușor cu elemente personalizate, va trebui, de asemenea, să fii foarte atent să nu stilizezi DOM-ul inserat, din cauza stilurilor în cascadă ale elementelor tale.
<!-- 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>
În ceea ce privește performanța, elementele personalizate sunt aproape la fel de rapide ca componentele web care nu sunt utilizate (adică conectarea foii de stil partajată în head
și utilizarea doar elementelor DOM native). Dintre toate tehnicile pe care le puteți folosi astăzi, aceasta este de departe cea mai rapidă.
Deoparte: un element personalizat este încă o componentă web pentru toate scopurile. Termenul „componente web” este folosit pentru a descrie patru tehnologii separate: elemente personalizate, etichete de șablon, importuri HTML și DOM-ul umbră.
Din păcate, termenul a fost folosit pentru a descrie orice folosește orice combinație a celor patru tehnologii. Acest lucru a dus la o mulțime de confuzii cu privire la ceea ce înseamnă oamenii când spun „componentă web”. Așa cum a descoperit Rob Dodson, mi s-a părut util să folosesc diferiți termeni atunci când vorbesc despre elemente personalizate cu și fără DOM-ul umbră.
Majoritatea dezvoltatorilor cu care am vorbit tind să asocieze termenul „componentă web” cu un element personalizat care utilizează DOM-ul umbră. Deci, în scopul acestui articol, am creat o distincție artificială între o componentă web și un element personalizat.
Utilizarea unei biblioteci de componente web
O altă soluție pe care o puteți folosi astăzi este o bibliotecă de componente web, cum ar fi Polymer, SkateJS sau X-Tag. Aceste biblioteci ajută la completarea găurilor suportului de astăzi și pot simplifica, de asemenea, codul necesar pentru a crea o componentă web. De asemenea, oferă, de obicei, funcții suplimentare care facilitează scrierea componentelor web.
De exemplu, Polymer vă permite să creați o componentă web simplă în doar câteva linii de JavaScript. Un avantaj suplimentar este că Polymer oferă o soluție pentru utilizarea DOM-ului umbră și a unei foi de stil partajate. Aceasta înseamnă că astăzi puteți crea componente web care partajează stiluri.
Pentru a face acest lucru, creați ceea ce ei numesc un modul de stil, care conține toate stilurile partajate. Poate fi fie o etichetă <style>
cu stilurile partajate inline, fie o etichetă <link rel=“import”>
care indică o foaie de stil partajată. În ambele cazuri, includeți stilurile în componenta dvs. web cu o etichetă <style include>
, iar apoi Polymer va analiza stilurile și le va adăuga ca etichetă <style>
inline la componenta dvs. web.
<!-- 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>
Singurul dezavantaj al folosirii unei biblioteci este că poate întârzia timpul de redare a componentelor dvs. web. Acest lucru nu ar trebui să fie o surpriză, deoarece descărcarea codului bibliotecii și procesarea acestuia necesită timp. Orice componente web de pe pagină nu pot începe redarea până când biblioteca nu termină procesarea.
În cazul Polymer, poate întârzia timpul de redare a paginii cu până la jumătate de secundă în comparație cu componentele web native. Un modul de stil care încorporează stilurile este puțin mai lent decât un modul de stil care leagă stilurile, iar încorporarea stilurilor direct în componenta web este la fel de rapidă ca și utilizarea unui modul de stil.
Din nou, Polymer nu face nimic special pentru a face timpul de randare mai lent. Descărcarea bibliotecii Polymer și procesarea tuturor caracteristicilor sale minunate, plus crearea tuturor legăturilor de șabloane, necesită timp. Este doar compromisul pe care va trebui să îl faceți pentru a utiliza o bibliotecă de componente web.
Rezultatele testelor de performanță arată că, folosind Polymer, componentele web se vor reda cu până la jumătate de secundă mai lent decât componentele web native.
Promisiunea Viitorului
Dacă niciuna dintre soluțiile actuale nu funcționează pentru tine, nu dispera. Dacă totul merge bine, în decurs de câteva luni până la câțiva ani, vom putea folosi stiluri comune folosind câteva abordări diferite.
Proprietăți personalizate
Proprietățile personalizate (sau variabilele CSS, așa cum au fost numite) sunt o modalitate de a seta și de a utiliza variabile în CSS. Această noțiune nu este nouă pentru preprocesoarele CSS, dar, ca caracteristică CSS nativă, proprietățile personalizate sunt de fapt mai puternice decât o variabilă de preprocesor.
Pentru a declara o proprietate personalizată, utilizați notația de proprietate personalizată a lui –my-variable: value
și accesați variabila folosind property: var(–my-variable)
. O proprietate personalizată în cascadă ca orice altă regulă CSS, astfel încât valoarea sa moștenește de la părintele ei și poate fi suprascrisă. Singura avertizare la proprietățile personalizate este că acestea trebuie declarate în interiorul unui selector și nu pot fi declarate singure, spre deosebire de o variabilă de preprocesor.
<style> /* Declare the custom property */ html { --main-bg-color: red; } /* Use the custom property */ input { background: var(--main-bg-color); } </style>
Un lucru care face proprietățile personalizate atât de puternice este capacitatea lor de a străpunge umbra DOM. Aceasta nu este aceeași idee cu selectoarele /deep/
și ::shadow
, deoarece nu își forțează drumul în componenta web. În schimb, autorul componentei web trebuie să folosească proprietatea personalizată în CSS-ul său pentru ca aceasta să fie aplicată. Aceasta înseamnă că un autor de componentă web poate crea un API de proprietate personalizat pe care consumatorii componentei web îl pot folosi pentru a-și aplica propriile stiluri.
<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>
Suportul de browser pentru proprietăți personalizate este surprinzător de bun. Singurul motiv pentru care nu este o soluție pe care o puteți folosi astăzi este că nu există polyfill funcțional fără Custom Elements versiunea 1. Echipa din spatele polifillului webcomponentjs lucrează în prezent să-l adauge, dar nu este încă lansat și într-o stare construită, ceea ce înseamnă că, dacă îți trimiți activele pentru producție, nu le poți folosi. Din câte am înțeles, va fi lansat cândva la începutul anului viitor.
Chiar și așa, proprietățile personalizate nu sunt o metodă bună pentru partajarea stilurilor între componentele web. Deoarece pot fi folosite doar pentru a declara o singură valoare a proprietății, componenta web ar trebui să încorporeze în continuare toate stilurile ghidului de stil, deși cu valorile lor înlocuite cu variabile.
Proprietățile personalizate sunt mai potrivite pentru opțiunile de tematică, decât pentru stilurile partajate. Din acest motiv, proprietățile personalizate nu sunt o soluție viabilă la problema noastră.
/* Folosește proprietatea personalizată */ input { background: var(–main-bg-color); } </stil>
Un lucru care face proprietățile personalizate atât de puternice este capacitatea lor de a străpunge umbra DOM. Aceasta nu este aceeași idee cu selectoarele /deep/
și ::shadow
, deoarece nu își forțează drumul în componenta web. În schimb, autorul componentei web trebuie să folosească proprietatea personalizată în CSS-ul său pentru ca aceasta să fie aplicată. Aceasta înseamnă că un autor de componentă web poate crea un API de proprietate personalizat pe care consumatorii componentei web îl pot folosi pentru a-și aplica propriile stiluri.
<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>
Suportul de browser pentru proprietăți personalizate este surprinzător de bun. Singurul motiv pentru care nu este o soluție pe care o puteți folosi astăzi este că nu există polyfill funcțional fără Custom Elements versiunea 1. Echipa din spatele polifillului webcomponentjs lucrează în prezent să-l adauge, dar nu este încă lansat și într-o stare construită, ceea ce înseamnă că, dacă îți trimiți activele pentru producție, nu le poți folosi. Din câte am înțeles, va fi lansat cândva la începutul anului viitor.
Chiar și așa, proprietățile personalizate nu sunt o metodă bună pentru partajarea stilurilor între componentele web. Deoarece pot fi folosite doar pentru a declara o singură valoare a proprietății, componenta web ar trebui să încorporeze în continuare toate stilurile ghidului de stil, deși cu valorile lor înlocuite cu variabile.
Proprietățile personalizate sunt mai potrivite pentru opțiunile de tematică, decât pentru stilurile partajate. Din acest motiv, proprietățile personalizate nu sunt o soluție viabilă la problema noastră.
@Apply Reguli
Pe lângă proprietățile personalizate, CSS primește și reguli @apply
. Regulile de aplicare sunt în esență mixuri pentru lumea CSS. Ele sunt declarate într-un mod similar cu proprietățile personalizate, dar pot fi utilizate pentru a declara grupuri de proprietăți în loc de doar valorile proprietăților. La fel ca proprietățile personalizate, valorile lor pot fi moștenite și suprascrise și trebuie declarate în interiorul unui selector pentru a funcționa.
<style> /* Declare rule */ html { --typography: { font: 16px Arial, sans-serif; color: #333333; } } /* Use rule */ input { @apply --typography; } </style>
Suportul de browser pentru regulile @apply
este practic inexistent. Chrome îl acceptă în prezent în spatele unui semnalizator de caracteristică (pe care nu l-am putut găsi), dar cam atât. De asemenea, nu există poliumplutură care funcționează din același motiv, deoarece nu există poliumplutură pentru proprietăți personalizate. Echipa webcomponentjs polyfill lucrează, de asemenea, pentru a adăuga reguli @apply
, împreună cu proprietăți personalizate, astfel încât ambele vor fi disponibile odată cu lansarea noii versiuni.
Spre deosebire de proprietățile personalizate, regulile @apply
sunt o soluție mult mai bună pentru partajarea stilurilor. Deoarece pot configura un grup de declarații de proprietate, le puteți utiliza pentru a configura stilul implicit pentru toate elementele native și apoi le puteți utiliza în interiorul componentei web. Pentru a face acest lucru, ar trebui să creați o regulă @apply
pentru fiecare element nativ.
Cu toate acestea, pentru a consuma stilurile, ar trebui să le aplicați manual fiecărui element nativ, ceea ce ar duplica declarația de stil în fiecare componentă web. Deși asta este mai bine decât încorporarea tuturor stilurilor, nici nu este foarte convenabil, deoarece devine boilerplate în partea de sus a fiecărei componente web, pe care trebuie să vă amintiți să o adăugați pentru ca stilurile să funcționeze corect.
/* 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>
Datorită necesității unui boilerplate extins, nu cred că regulile @apply
ar fi o soluție bună pentru partajarea stilurilor între componentele web. Sunt o soluție excelentă pentru tematică, totuși.
în Shadow DOM
Conform specificațiilor componentei web, browserele ignoră orice etichetă <link rel=“stylesheet”>
din DOM-ul umbră, tratându-le exact ca în interiorul unui fragment de document. Acest lucru ne-a împiedicat să ne putem conecta în orice stil partajat în componentele noastre web, ceea ce a fost regretabil – adică până acum câteva luni, când Grupul de lucru pentru componente web a propus ca etichetele <link rel=“stylesheet”>
să funcționeze în umbra DOM. După doar o săptămână de discuții, toți au fost de acord că ar trebui, iar câteva zile mai târziu au adăugat-o la specificația 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>
Dacă acest lucru sună puțin prea rapid pentru ca grupul de lucru să cadă de acord asupra unei specificații, asta pentru că nu a fost o propunere nouă. A face ca etichetele de link
să funcționeze în umbră DOM a fost de fapt propusă cu cel puțin trei ani în urmă, dar a fost întârziat până când s-au putut asigura că nu era o problemă pentru performanță.
Dacă acceptarea propunerii nu este suficient de interesantă, Chrome 55 (în prezent Chrome Canary) a adăugat funcționalitatea inițială de a face etichetele de link
să funcționeze în DOM-ul umbră. Se pare chiar că această funcționalitate a ajuns în versiunea actuală de Chrome. Chiar și Safari a implementat caracteristica în Safari 18.
Posibilitatea de a conecta stilurile partajate este de departe cea mai convenabilă metodă de partajare a stilurilor între componentele web. Tot ce trebuie să faceți este să creați eticheta de link
și toate elementele native vor fi stilate în consecință, fără a necesita nicio muncă suplimentară.
Desigur, modul în care producătorii de browser implementează caracteristica va determina dacă această soluție este viabilă. Pentru ca acest lucru să funcționeze corect, etichetele de link
ar trebui să fie deduplicate, astfel încât mai multe componente web care solicită același fișier CSS ar provoca o singură solicitare HTTP. CSS-ul ar trebui, de asemenea, analizat o singură dată, astfel încât fiecare instanță a componentei web să nu recalculeze stilurile partajate, ci să reutilizeze stilurile calculate.
Chrome le face deja pe ambele. Deci, dacă toți ceilalți producători de browsere îl implementează în același mod, atunci etichetele de link
care lucrează în DOM-ul umbră ar rezolva cu siguranță problema modului de partajare a stilurilor între componentele web.
Foi de stil constructive
S-ar putea să vă fie greu de crezut, deoarece nici măcar nu l-am prins încă, dar o etichetă de link
care funcționează în DOM-ul umbră nu este o soluție pe termen lung. În schimb, este doar o soluție pe termen scurt pentru a ne duce la soluția reală: foi de stil construibile.
Foile de stil construibile sunt o propunere pentru a permite crearea de obiecte StyleSheet
în JavaScript printr-o funcție de constructor. Foaia de stil construită ar putea fi apoi adăugată la shadow DOM printr-un API, care ar permite shadow DOM să folosească un set de stiluri partajate.
Din păcate, asta este tot ce am putut aduna din propunere. Am încercat să aflu mai multe informații despre ce sunt foile de stil construibile întrebând Grupul de lucru Componente web, dar m-au redirecționat către lista de corespondență a Grupului de lucru CSS al W3C, unde am întrebat din nou, dar nimeni nu a răspuns. Nici nu mi-am putut da seama cum progresa propunerea, pentru că nu a fost actualizată de peste doi ani.
Chiar și așa, Web Components Working Group îl folosește ca soluție pentru partajarea stilurilor între componentele web. Sperăm că fie propunerea va fi actualizată, fie Grupul de lucru pentru componente web va publica mai multe informații despre aceasta și adoptarea ei. Până atunci, soluția „pe termen lung” pare că nu se va întâmpla în viitorul apropiat.
Lecții învățate
După luni de cercetare și teste, sunt destul de plin de speranță în viitor. Este reconfortant să știi că după ani în care nu ai o soluție pentru partajarea stilurilor între componentele web, există în sfârșit răspunsuri. Aceste răspunsuri s-ar putea să nu fie stabilite pentru câțiva ani, dar cel puțin sunt acolo.
Dacă doriți să utilizați un ghid de stil partajat pentru a stila componentele web astăzi, fie nu puteți utiliza shadow DOM și, în schimb, puteți crea elemente personalizate, fie puteți utiliza o bibliotecă de componente web care completează suportul pentru partajarea stilurilor. Ambele soluții au avantajele și dezavantajele lor, așa că utilizați cea care funcționează cel mai bine pentru proiectul dvs.
Dacă decideți să așteptați un timp înainte de a explora componentele web, atunci în câțiva ani ar trebui să avem câteva soluții grozave pentru a împărtăși stilurile între ele. Așadar, continuați să verificați cum evoluează.
Lucruri de reținut
Rețineți câteva lucruri dacă decideți să utilizați astăzi elemente personalizate sau componente web.
Cel mai important, specificația componentelor web este încă în curs de dezvoltare activ, ceea ce înseamnă că lucrurile se pot schimba și se vor schimba. Componentele web sunt încă extrem de avansate, așa că fiți pregătit să rămâneți cu atenție pe măsură ce vă dezvoltați cu ele.
Dacă decideți să utilizați shadow DOM, știți că este destul de lent și lipsit de performanță în browserele multicompletate. Din acest motiv, dezvoltatorii Polymer și-au creat implementarea umbrită DOM și au făcut-o implicită.
Chrome, Opera și, recent, Safari sunt singurele browsere care acceptă versiunea shadow DOM 0. Firefox este încă în dezvoltare, deși l-a susținut în spatele unui experiment încă din versiunea 29. Microsoft îl ia în considerare încă pentru Edge și îl are ca un prioritate ridicată pe foaia sa de parcurs.
Cu toate acestea, shadow DOM versiunea 0 este specificația veche. Shadow DOM versiunea 1 este cea nouă și doar Chrome, Safari și Opera o acceptă pe deplin. Ca să nu mai vorbim de faptul că versiunea 0 a elementelor personalizate a trecut prin aceeași actualizare și doar Chrome acceptă pe deplin elementele personalizate versiunea 1, în timp ce previzualizarea tehnică Safari o acceptă începând cu versiunea 17. Elementele personalizate versiunea 1 are câteva modificări majore în modul în care sunt scrise componentele web, deci asigurați-vă că înțelegeți pe deplin ce înseamnă asta.
În cele din urmă, polifill-ul webcomponentjs acceptă doar implementarea versiunii 0 a DOM-ului umbră și a elementelor personalizate. O ramură a versiunii 1 a polyfill va accepta versiunea 1, dar nu a fost încă lansată.