Houdini: Poate cea mai incitantă dezvoltare din CSS despre care n-ai auzit niciodată
Publicat: 2022-03-10Ați dorit vreodată să utilizați o anumită caracteristică CSS, dar nu ați făcut-o pentru că nu a fost pe deplin acceptată în toate browserele ? Sau, mai rău, a fost acceptat în toate browserele, dar suportul era cu erori, inconsecvent sau chiar complet incompatibil? Dacă ți s-a întâmplat asta - și pariez că s-a întâmplat - atunci ar trebui să-ți pese de Houdini.
Houdini este un nou grup de lucru W3C al cărui scop final este să facă această problemă să dispară pentru totdeauna. Intenționează să facă acest lucru prin introducerea unui nou set de API-uri care, pentru prima dată, le va oferi dezvoltatorilor puterea de a extinde CSS în sine și instrumentele pentru a se conecta la procesul de stilare și aspect al motorului de randare al unui browser .
Citiți suplimentare despre SmashingMag:
- De ce ar trebui să încetați să instalați mediul WebDev local
- Viitorul CSS: proprietăți experimentale CSS
- 53 CSS-Tehnici fără de care nu ai putea trăi
Dar ce înseamnă asta, în mod concret? Este chiar o idee bună? Și cum ne va ajuta pe noi dezvoltatorii să construim site-uri web acum și în viitor?
În acest articol, voi încerca să răspund la aceste întrebări. Dar înainte de a o face, este important să clarific care sunt problemele astăzi și de ce este atât de nevoie de schimbare. Apoi voi vorbi mai precis despre modul în care Houdini va rezolva aceste probleme și voi enumera câteva dintre caracteristicile mai interesante în prezent în dezvoltare. În cele din urmă, voi oferi câteva lucruri concrete pe care noi, în calitate de dezvoltatori web, le putem face astăzi pentru a ajuta Houdini să devină realitate.
Ce probleme încearcă Houdini să rezolve?
De fiecare dată când scriu un articol sau construiesc o demonstrație care prezintă o nouă funcție CSS, inevitabil, cineva din comentarii sau pe Twitter va spune ceva de genul: „Este minunat! Păcat că nu îl vom putea folosi încă 10 ani.”
Oricât de enervante și neconstructive sunt comentariile de genul acesta, înțeleg sentimentul. Din punct de vedere istoric, au fost nevoie de ani pentru ca propunerile de caracteristici să obțină o adoptare pe scară largă. Și motivul este că, de-a lungul istoriei web-ului, singura modalitate de a obține o nouă caracteristică adăugată la CSS a fost să treci prin procesul standardelor.

Deși nu am absolut nimic împotriva procesului standardelor, nu se poate nega că poate dura mult timp!
De exemplu, flexbox a fost propus pentru prima dată în 2009, iar dezvoltatorii încă se plâng că nu îl pot folosi astăzi din cauza lipsei de suport pentru browser. Desigur, această problemă dispare încet, deoarece aproape toate browserele moderne se actualizează acum automat; dar chiar și cu browserele moderne, va exista întotdeauna un decalaj între propunere și disponibilitatea generală a unei funcții.
Interesant, acest lucru nu este cazul în toate zonele web. Luați în considerare cum au funcționat lucrurile recent în JavaScript:

În acest scenariu, timpul dintre a avea o idee și a ajunge să o folosești în producție poate fi uneori o chestiune de câteva zile. Adică, folosesc deja funcțiile async
/ await
în producție, iar această caracteristică nu a fost implementată nici măcar într-un singur browser!
De asemenea, puteți vedea o diferență uriașă în sentimentele generale ale acestor două comunități. În comunitatea JavaScript, citiți articole în care oamenii se plâng că lucrurile se mișcă prea repede. În CSS, pe de altă parte, auziți oameni deplângându-se de inutilitatea de a învăța ceva nou din cauza cât timp va trece până când îl vor putea folosi efectiv.
Deci, de ce nu scriem mai multe Polyfills CSS?
La prima gândire, scrierea mai multor polyfill-uri CSS ar putea părea a fi răspunsul. Cu polifillări bune, CSS s-ar putea mișca la fel de repede ca JavaScript, nu?
Din păcate, nu este atât de simplu. Polyfilling CSS este incredibil de greu și, în cele mai multe cazuri, imposibil de făcut într-un mod care să nu distrugă complet performanța.
JavaScript este un limbaj dinamic, ceea ce înseamnă că puteți utiliza JavaScript pentru a completa JavaScript. Și pentru că este atât de dinamic, este extrem de extensibil. CSS, pe de altă parte, poate fi folosit rar pentru a polifill CSS. În unele cazuri, puteți transpila CSS în CSS într-un pas de construire (PostCSS face acest lucru); dar dacă doriți să completați orice lucru care depinde de structura DOM sau de aspectul sau poziția unui element, atunci ar trebui să rulați partea logică a clientului a polifillului.
Din păcate, browserul nu face acest lucru ușor.
Graficul de mai jos oferă o schiță de bază a modului în care browserul dvs. trece de la primirea unui document HTML la afișarea pixelilor pe ecran. Pașii colorați în albastru arată unde JavaScript are puterea de a controla rezultatele:

Poza este destul de sumbră. În calitate de dezvoltator, nu aveți control asupra modului în care browserul analizează HTML și CSS și le transformă în modelul de obiecte DOM și CSS (CSSOM). Nu ai control asupra cascadei. Nu aveți control asupra modului în care browserul alege să așeze elementele în DOM sau asupra modului în care pictează acele elemente vizual pe ecran. Și nu aveți control asupra a ceea ce face compozitorul.
Singura parte a procesului la care aveți acces complet este DOM. CSSOM este oarecum deschis; cu toate acestea, pentru a cita site-ul web Houdini, acesta este „subspecificat, inconsecvent între browsere și lipsește funcții critice”.
De exemplu, CSSOM din browserele de astăzi nu vă va afișa reguli pentru foile de stil cu origini încrucișate și va elimina pur și simplu orice reguli sau declarații CSS pe care nu le înțelege, ceea ce înseamnă că dacă doriți să completați o funcție într-un browser asta nu o acceptă, nu poți folosi CSSOM. În schimb, trebuie să parcurgeți DOM, să găsiți etichetele <style>
și/sau <link rel=“stylesheet”>
, să obțineți singur CSS-ul, să îl analizați, să îl rescrieți și apoi să îl adăugați înapoi în DOM.
Desigur, actualizarea DOM-ului înseamnă, de obicei, că browserul trebuie să parcurgă din nou întreaga cascadă, aspect, vopsire și pași compoziți.

Deși trebuie să redați complet o pagină ar putea să nu pară un succes de performanță (în special pentru unele site-uri), luați în considerare cât de des ar trebui să se întâmple acest lucru. Dacă logica polyfill-ului dvs. trebuie să ruleze ca răspuns la evenimente precum evenimentele de defilare, redimensionarea ferestrei, mișcările mouse-ului, evenimentele de la tastatură - într-adevăr oricând orice se schimbă - atunci lucrurile vor fi vizibil, uneori chiar paralizant, lente.
Acest lucru devine și mai rău când îți dai seama că majoritatea polyfillurilor CSS de astăzi includ propriul lor parser CSS și propria lor logică în cascadă. Și pentru că analizarea și cascada sunt de fapt lucruri foarte complicate, aceste poliumpleri sunt, de obicei, mult prea mari sau mult prea defectuoase.
Pentru a rezuma tot ce am spus mai concis: dacă doriți ca browserul să facă ceva diferit de ceea ce crede că ar trebui să facă (având în vedere CSS-ul pe care l-ați dat), atunci trebuie să găsiți o modalitate de a-l falsifica prin actualizarea și modificarea DOM-ul însuți. Nu aveți acces la ceilalți pași din conducta de randare.
Dar de ce aș dori vreodată să modific motorul intern de randare al browserului?
Aceasta este, pentru mine, cea mai importantă întrebare la care trebuie să răspund în tot acest articol. Așadar, dacă ați căutat lucrurile până acum, citiți această parte încet și cu atenție!
După ce am privit ultima secțiune, sunt sigur că unii dintre voi s-au gândit: „Nu am nevoie de asta! Doar construiesc pagini web normale. Nu încerc să sparg elementele interne ale browserului sau să construiesc ceva super fantezist, experimental sau de ultimă generație.”
Dacă vă gândiți la asta, atunci vă îndemn cu tărie să vă întoarceți o secundă și să examinați cu adevărat tehnologiile pe care le-ați folosit pentru a construi site-uri web de-a lungul anilor. Dorința de a avea acces și a legături în procesul de stilare al browserului nu înseamnă doar construirea de demo-uri fanteziste, ci este despre a oferi dezvoltatorilor și autorilor de cadre puterea de a face două lucruri principale:
- pentru a normaliza diferențele între browsere,
- să inventeze sau să completeze noi funcții, astfel încât oamenii să le poată folosi astăzi.
Dacă ați folosit vreodată o bibliotecă JavaScript, cum ar fi jQuery, atunci ați beneficiat deja de această abilitate! De fapt, acesta este unul dintre principalele puncte de vânzare ale aproape tuturor bibliotecilor și cadrelor front-end de astăzi. Cele mai populare cinci depozite JavaScript și DOM de pe GitHub — AngularJS, D3, jQuery, React și Ember — fac toate eforturile pentru a normaliza diferențele dintre browsere, astfel încât să nu trebuiască să vă gândiți la asta. Fiecare expune un singur API și pur și simplu funcționează.
Acum, gândiți-vă la CSS și la toate problemele sale între browsere. Chiar și cadrele CSS populare, cum ar fi Bootstrap și Foundation, care pretind compatibilitatea între browsere, nu normalizează erorile între browsere, ci doar le evită. Iar erorile între browsere în CSS nu sunt doar un lucru din trecut. Chiar și astăzi, cu noi module de layout, cum ar fi flexbox, ne confruntăm cu multe incompatibilități între browsere.
Concluzia este să vă imaginați cât de mult mai plăcută ar fi viața dvs. de dezvoltare dacă ați putea folosi orice proprietate CSS și ați ști sigur că va funcționa, exact la fel, în fiecare browser. Și gândiți-vă la toate funcțiile noi despre care citiți în postările de pe blog sau auziți despre conferințe și întâlniri - lucruri precum grile CSS, puncte de snap CSS și poziționare lipicioasă. Imaginați-vă dacă le-ați putea folosi pe toate astăzi și într-un mod care ar fi la fel de performant ca și caracteristicile CSS native. Și tot ce trebuie să faceți este să luați codul din GitHub.

Acesta este visul lui Houdini. Acesta este viitorul pe care grupul de lucru încearcă să îl facă posibil.
Așadar, chiar dacă nu intenționați să scrieți vreodată un polyfill CSS sau să dezvoltați o caracteristică experimentală, probabil că ați dori ca alți oameni să poată face acest lucru - deoarece odată ce aceste polyfill-uri există, toată lumea beneficiază de pe urma lor.
Ce caracteristici Houdini sunt în curs de dezvoltare?
Am menționat mai sus că dezvoltatorii au foarte puține puncte de acces în conducta de randare a browserului. Într-adevăr, singurele locuri sunt DOM și, într-o oarecare măsură, CSSOM.
Pentru a rezolva această problemă, grupul de lucru Houdini a introdus câteva specificații noi care, pentru prima dată, vor oferi dezvoltatorilor acces la celelalte părți ale conductei de randare. Graficul de mai jos arată conducta și ce specificații noi pot fi folosite pentru a modifica ce pași. (Rețineți că specificațiile în gri sunt planificate, dar nu au fost încă scrise.)

Următoarele câteva secțiuni oferă o scurtă prezentare generală a fiecărei specificații noi și a tipurilor de capabilități pe care le oferă. De asemenea, ar trebui să remarc că alte specificații nu sunt menționate în acest articol; pentru lista completă, consultați depozitul GitHub al schițelor lui Houdini.
CSS Parser API
API-ul CSS Parser nu este în prezent scris; Deci, mare parte din ceea ce spun s-ar putea schimba cu ușurință, dar ideea de bază este că le permite dezvoltatorilor să extindă parserul CSS și să-i spună despre noile constructe - de exemplu, noi reguli media, noi pseudo-clase, imbricare, @extends
, @apply
, etc.
Odată ce analizatorul știe despre aceste noi constructe, le poate pune la locul potrivit în CSSOM, în loc să le arunce doar.
API CSS Properties and Values
CSS are deja proprietăți personalizate și, așa cum am mai spus, sunt foarte încântat de posibilitățile pe care le deblochează. API-ul CSS Properties and Values duce proprietățile personalizate un pas mai departe și le face și mai utile prin adăugarea de tipuri.
Există o mulțime de lucruri grozave despre adăugarea de tipuri la proprietăți personalizate, dar poate cel mai mare argument de vânzare este că tipurile vor permite dezvoltatorilor să facă tranziția și să anime proprietățile personalizate, ceva ce nu putem face astăzi.
Luați în considerare acest exemplu:
body { --primary-theme-color: tomato; transition: --primary-theme-color 1s ease-in-out; } body.night-theme { --primary-theme-color: darkred; }
În codul de mai sus, dacă clasa night-theme
este adăugată la elementul <body>
, atunci fiecare element de pe pagină care face referire la valoarea proprietății –primary-theme-color
va trece încet de la tomato
la darkred
. Dacă ai vrea să faci asta astăzi, ar trebui să scrii manual tranziția pentru fiecare dintre aceste elemente, deoarece nu poți face tranziția proprietății în sine.
O altă caracteristică promițătoare a acestui API este capacitatea de a înregistra un „cârlig de aplicare”, care oferă dezvoltatorilor o modalitate de a modifica valoarea finală a unei proprietăți personalizate pe elemente după finalizarea pasului în cascadă, ceea ce ar putea fi o caracteristică foarte utilă pentru polyfills.
OM tip CSS
OM tip CSS poate fi considerat ca versiunea 2 a CSSOM-ului actual. Scopul său este să rezolve multe probleme cu modelul actual și să includă funcții adăugate de noul API de analiză CSS și API-ul CSS Properties and Values.
Un alt obiectiv major al Typed OM este îmbunătățirea performanței. Conversia valorilor șirurilor CSSOM curente în reprezentări JavaScript scrise în mod semnificativ ar produce câștiguri substanțiale de performanță.
CSS Layout API
API-ul CSS Layout le permite dezvoltatorilor să-și scrie propriile module de aspect. Și prin „modul de aspect”, mă refer la orice poate fi transmis proprietății de display
CSS. Acest lucru le va oferi dezvoltatorilor, pentru prima dată, o modalitate de aranjare care este la fel de performantă ca modulele de layout native, cum ar fi display: flex
și display: table
.
Ca exemplu de caz de utilizare, biblioteca de layout Masonry arată în ce măsură dezvoltatorii sunt dispuși să meargă astăzi pentru a realiza layout-uri complexe care nu sunt posibile numai cu CSS. Deși aceste aspecte sunt impresionante, din păcate, ele suferă de probleme de performanță, în special pe dispozitivele mai puțin puternice.
API-ul CSS Layout funcționează oferind dezvoltatorilor o metodă registerLayout
care acceptă un nume de aspect (care este folosit ulterior în CSS) și o clasă JavaScript care include toată logica aspectului. Iată un exemplu de bază despre cum ați putea defini masonry
prin registerLayout
:
registerLayout('masonry', class { static get inputProperties() { return ['width', 'height'] } static get childrenInputProperties() { return ['x', 'y', 'position'] } layout(children, constraintSpace, styleMap, breakToken) { // Layout logic goes here. } }
Dacă nimic din exemplul de mai sus nu are sens pentru tine, nu-ți face griji. Principalul lucru de care să-ți pese este codul din exemplul următor. După ce ați descărcat fișierul masonry.js
și l-ați adăugat pe site-ul dvs. web, puteți scrie CSS astfel și totul va funcționa:
body { display: layout('masonry'); }
CSS Paint API
API-ul CSS Paint este foarte asemănător cu API-ul Layout de mai sus. Oferă o metodă registerPaint
care funcționează la fel ca metoda registerLayout
. Dezvoltatorii pot folosi apoi funcția paint()
în CSS oriunde este așteptată o imagine CSS și pot transmite numele care a fost înregistrat.
Iată un exemplu simplu care pictează un cerc colorat:
registerPaint('circle', class { static get inputProperties() { return ['--circle-color']; } paint(ctx, geom, properties) { // Change the fill color. const color = properties.get('--circle-color'); ctx.fillStyle = color; // Determine the center point and radius. const x = geom.width / 2; const y = geom.height / 2; const radius = Math.min(x, y); // Draw the circle \o/ ctx.beginPath(); ctx.arc(x, y, radius, 0, 2 * Math.PI, false); ctx.fill(); } });
Și poate fi folosit în CSS astfel:
.bubble { --circle-color: blue; background-image: paint('circle'); }
Acum, elementul .bubble
va fi afișat cu un cerc albastru ca fundal. Cercul va fi centrat și de aceeași dimensiune ca și elementul însuși, oricare ar fi acesta.
Worklet-uri
Multe dintre specificațiile enumerate mai sus prezintă exemple de cod (de exemplu, registerLayout
și registerPaint
). Dacă vă întrebați unde ați pune acel cod, răspunsul este în scripturile worklet-urilor.
Worklet-urile sunt similare lucrătorilor web și vă permit să importați fișiere script și să rulați cod JavaScript care (1) poate fi invocat în diferite puncte ale conductei de randare și (2) este independent de firul principal.
Scripturile de worklet vor restricționa puternic tipurile de operațiuni pe care le puteți face, ceea ce este cheia pentru asigurarea performanței ridicate.
Defilare compusă și animație
Deși nu există încă o specificație oficială pentru derularea și animația compusă, este de fapt una dintre cele mai cunoscute și mai așteptate caracteristici Houdini. Eventualele API-uri vor permite dezvoltatorilor să ruleze logica într-un worklet de compozitor, în afara firului principal, cu suport pentru modificarea unui subset limitat de proprietăți ale unui element DOM. Acest subset va include numai proprietăți care pot fi citite sau setate fără a forța motorul de randare să recalculeze aspectul sau stilul (de exemplu, transformarea, opacitatea, deplasarea derulării).
Acest lucru va permite dezvoltatorilor să creeze animații foarte performante bazate pe derulare și introducere, cum ar fi antete de defilare lipicioase și efecte de paralaxă. Puteți citi mai multe despre cazurile de utilizare pe care aceste API-uri încearcă să le rezolve pe GitHub.
Deși nu există încă o specificație oficială, dezvoltarea experimentală a început deja în Chrome. De fapt, echipa Chrome implementează în prezent puncte de snap CSS și poziționare sticky folosind primitivele pe care aceste API-uri le vor expune în cele din urmă. Acest lucru este uimitor, deoarece înseamnă că API-urile Houdini sunt suficient de performante încât să fie construite noi funcții Chrome pe deasupra lor. Dacă mai aveai vreo teamă că Houdini nu va fi la fel de rapid ca nativ, doar acest fapt ar trebui să te convingă de contrariul.
Pentru a vedea un exemplu real, Surma a înregistrat o demonstrație video care rulează pe o versiune internă a Chrome. Demo-ul imită comportamentul antetului de defilare văzut în aplicațiile mobile native ale Twitter. Pentru a vedea cum funcționează, consultați codul sursă.
Ce poți face acum?
După cum am menționat, cred că tuturor celor care construiesc site-uri web ar trebui să le pese de Houdini; ne va face viața mult mai ușoară în viitor. Chiar dacă nu utilizați niciodată o specificație Houdini în mod direct, aproape sigur veți folosi ceva construit peste una.
Și deși acest viitor s-ar putea să nu fie imediat, este probabil mai aproape decât credem mulți dintre noi. Reprezentanții tuturor furnizorilor importanți de browsere au fost la ultima întâlnire față în față a Houdini, la Sydney, la începutul acestui an, și au existat foarte puține dezacorduri cu privire la ce să construim sau cum să procedezi.
Din câte mi-aș putea da seama, nu se pune problema dacă Houdini va fi un lucru, ci când, și aici intrați cu toții.
Furnizorii de browsere, ca toți ceilalți care creează software, trebuie să acorde prioritate noilor funcții. Și această prioritate este adesea o funcție a cât de mult își doresc utilizatorii acele funcții.
Deci, dacă vă pasă de extensibilitatea stilului și aspectului pe web și dacă doriți să trăiți într-o lume în care puteți utiliza noile funcții CSS fără a fi nevoie să așteptați ca acestea să treacă prin procesul standardelor, discutați cu membrii echipele de relații cu dezvoltatorii pentru browserele pe care le utilizați și spuneți-le că doriți acest lucru.
Celălalt mod în care puteți ajuta este oferind cazuri de utilizare în lumea reală - lucruri pe care doriți să le puteți face cu stilul și aspectul care sunt dificil sau imposibil de realizat astăzi. Câteva dintre schițele de pe GitHub au documente de utilizare și puteți trimite o cerere de extragere pentru a contribui cu ideile dvs. Dacă un document nu există, puteți începe unul.
Membrii grupului de lucru Houdini (și W3C în general) chiar își doresc o contribuție atentă de la dezvoltatorii web. Majoritatea oamenilor care participă la procesul de scriere a specificațiilor sunt ingineri care lucrează pe browsere. Adesea nu sunt dezvoltatori web profesioniști, ceea ce înseamnă că nu știu întotdeauna unde sunt punctele dureroase.
Ei depind de noi să le spunem.
Resurse și linkuri
- CSS-TAG Houdini Editor Drafts, W3C Cea mai recentă versiune publică a tuturor proiectelor Houdini
- Specificații CSS-TAG Houdini Task Force, GitHub Depozitul oficial Github unde au loc actualizările și dezvoltarea specificațiilor
- Houdini Samples, exemple de cod GitHub care prezintă și experimentează cu posibile API-uri
- Lista de corespondență Houdini, W3C Un loc pentru a pune întrebări generale
Mulțumiri speciale membrilor Houdini Ian Kilpatrick și Shane Stephens pentru revizuirea acestui articol.