O prezentare practică a CSS Houdini

Publicat: 2022-03-10
Rezumat rapid ↬ Houdini, un termen umbrelă pentru colecția de API-uri de browser, își propune să aducă îmbunătățiri semnificative procesului de dezvoltare web și dezvoltării standardelor CSS în general. Dezvoltatorii front-end vor putea extinde CSS-ul cu noi funcții folosind JavaScript, se vor conecta la motorul de randare CSS și vor putea spune browserului cum să aplice CSS în timpul procesului de randare. Compatibilitatea browserului Houdini se îmbunătățește și unele API-uri sunt disponibile pentru utilizare astăzi, așa că este un moment bun pentru a vă familiariza cu ele și a experimenta. Vom arunca o privire asupra fiecărei părți a Houdini, a suportului său actual pentru browser și vom vedea cum pot fi folosite astăzi folosind îmbunătățirea progresivă.

Este nevoie de mult timp pentru ca o nouă funcție CSS sau o îmbunătățire să treacă de la o versiune inițială la o funcție CSS complet acceptată și stabilă, pe care dezvoltatorii o pot folosi. Polifillările bazate pe JavaScript pot fi folosite ca un substitut pentru lipsa suportului pentru browser pentru a utiliza noile funcții CSS înainte de a fi implementate oficial. Dar sunt defecte în majoritatea cazurilor. De exemplu, scrollsnap-polyfill este una dintre numeroasele polyfill care pot fi utilizate pentru a remedia inconsecvențele de compatibilitate cu browserul pentru specificația CSS Scroll Snap. Dar chiar și acea soluție are unele limitări, erori și inconsecvențe.

Potențialul dezavantaj al utilizării polyfills este că acestea pot avea un impact negativ asupra performanței și sunt dificil de implementat corespunzător. Acest dezavantaj este legat de DOM și CSSOM ale browserului. Browserul creează un DOM (Document Object Model) din markup HTML și, în mod similar, a creat CSSOM (CSS Object Model) din markup CSS. Acești doi arbori de obiecte sunt independenți unul de celălalt. JavaScript funcționează pe DOM și are acces foarte limitat la CSSOM.

Soluțiile JavaScript Polyfill rulează numai după ce ciclul inițial de randare a fost finalizat, adică când au fost create atât DOM, cât și CSSOM și documentul s-a terminat de încărcat. După ce Polyfill face modificări stilurilor în DOM (prin alinierea lor), face ca procesul de randare să ruleze din nou și întreaga pagină se redă din nou. Impactul negativ asupra performanței devine și mai evident dacă se bazează pe metoda requestAnimationFrame sau depind de interacțiunile utilizatorului, cum ar fi evenimentele de defilare.

Un alt obstacol în dezvoltarea web sunt diversele constrângeri impuse de standardele CSS . De exemplu, există doar un număr limitat de proprietăți CSS care pot fi animate nativ. CSS știe cum să anime culorile în mod nativ, dar nu știe cum să anime degradeurile. Întotdeauna a existat nevoia de a inova și de a crea experiențe web impresionante, depășind granițele, în ciuda limitărilor tehnologice. Acesta este motivul pentru care dezvoltatorii tind adesea să graviteze spre utilizarea unor soluții mai puțin decât ideale sau JavaScript pentru a implementa stiluri și efecte mai avansate care în prezent nu sunt acceptate de CSS, cum ar fi aspectul zidăriei, efecte 3D avansate, animație avansată, tipografie fluidă, gradienți animați, elemente select stilate etc.

Pare imposibil ca specificațiile CSS să țină pasul cu diferitele cerințe ale caracteristicilor din industrie, cum ar fi mai mult control asupra animațiilor, trunchiere îmbunătățită a textului, opțiune de stil mai bună pentru elemente de input și select , mai multe opțiuni display , mai multe opțiuni de filter etc.

Care ar putea fi soluția potențială? Oferiți dezvoltatorilor o modalitate nativă de a extinde CSS folosind diverse API-uri . În acest articol, vom arunca o privire asupra modului în care dezvoltatorii frontend pot face asta folosind API-urile Houdini, JavaScript și CSS. În fiecare secțiune, vom examina fiecare API individual, vom verifica compatibilitatea browserului și starea curentă a specificațiilor și vom vedea cum pot fi implementate astăzi folosind îmbunătățirea progresivă.

Mai multe după săritură! Continuați să citiți mai jos ↓

Ce este Houdini?

Houdini, un termen umbrelă pentru colecția de API-uri de browser, își propune să aducă îmbunătățiri semnificative procesului de dezvoltare web și dezvoltării standardelor CSS în general. Dezvoltatorii vor putea să extindă CSS-ul cu noi funcții folosind JavaScript, să se cupleze la motorul de randare CSS și să spună browserului cum să aplice CSS în timpul procesului de randare. Acest lucru va avea ca rezultat o performanță și o stabilitate semnificativ mai bune decât utilizarea polifiltrelor obișnuite.

Specificația Houdini constă din două grupuri de API - API-uri de nivel înalt și API -uri de nivel scăzut .

API-urile de nivel înalt sunt strâns legate de procesul de randare al browserului (stil → aspect → vopsea → compozit). Aceasta include:

  • Paint API
    Un punct de extensie pentru pasul de redare a picturii al browserului unde sunt determinate proprietățile vizuale (culoare, fundal, chenar etc.).
  • Layout API
    Un punct de extensie pentru pasul de randare a aspectului browserului în care sunt determinate dimensiunile elementului, poziția și alinierea.
  • API de animație
    Un punct de extensie pentru etapa de randare compusă a browserului în care straturile sunt desenate pe ecran și animate.

API-urile de nivel scăzut formează o bază pentru API-urile de nivel înalt. Aceasta include:

  • API-ul Typed Object Model
  • API-ul Proprietăți și valori personalizate
  • API-ul Font Metrics
  • Worklet-uri

Unele API-uri Houdini sunt deja disponibile pentru utilizare în unele browsere, iar alte API-uri urmează să urmeze exemplul atunci când sunt gata de lansare.

Viitorul CSS

Spre deosebire de specificațiile obișnuite ale caracteristicilor CSS care au fost introduse până acum, Houdini iese în evidență permițând dezvoltatorilor să extindă CSS într-un mod mai nativ. Înseamnă asta că specificațiile CSS nu vor mai evolua și nu vor fi lansate noi implementări oficiale ale caracteristicilor CSS? Ei bine, nu este cazul. Scopul lui Houdini este de a ajuta procesul de dezvoltare a caracteristicilor CSS, permițând dezvoltatorilor să creeze prototipuri funcționale care pot fi ușor standardizate.

În plus, dezvoltatorii vor putea să partajeze worklet-urile CSS open-source mai ușor și cu mai puțină nevoie de remedieri de erori specifice browserului.

API-ul Typed Object Model

Înainte ca Houdini să fie introdus, singura modalitate prin care JavaScript poate interacționa cu CSS era parsarea CSS reprezentată ca valori de șir și modificarea acestora. Analizarea și suprascrierea manuală a stilurilor poate fi dificilă și predispusă la erori din cauza tipului de valoare care trebuie schimbat înainte și înapoi și a unității de valoare care trebuie adăugată manual atunci când se atribuie o nouă valoare.

 selectedElement.style.fontSize = newFontSize + "px"; // newFontSize = 20 console.log(selectedElement.style.fontSize); // "20px"

API-ul Typed Object Model (Typed OM) adaugă mai multă semnificație semantică valorilor CSS prin expunerea lor ca obiecte JavaScript tastate. Îmbunătățește semnificativ codul aferent și îl face mai performant, mai stabil și mai ușor de întreținut. Valorile CSS sunt reprezentate de interfața CSSUnitValue care constă dintr-o valoare și o proprietate de unitate.

 { value: 20, unit: "px" }

Această nouă interfață poate fi utilizată cu următoarele proprietăți noi:

  • computedStyleMap() : pentru analizarea stilurilor calculate (non-inline). Aceasta este o metodă a elementului selectat care trebuie invocată înainte de a analiza sau de a utiliza alte metode.
  • attributeStyleMap : pentru analizarea și modificarea stilurilor inline. Aceasta este o proprietate care este disponibilă pentru un element selectat.
 // Get computed styles from stylesheet (initial value) selectedElement.computedStyleMap().get("font-size"); // { value: 20, unit: "px"} // Set inline styles selectedElement.attributeStyleMap.set("font-size", CSS.em(2)); // Sets inline style selectedElement.attributeStyleMap.set("color", "blue"); // Sets inline style // Computed style remains the same (initial value) selectedElement.computedStyleMap().get("font-size"); // { value: 20, unit: "px"} // Get new inline style selectedElement.attributeStyleMap.get("font-size"); // { value: 2, unit: "em"}

Observați cum sunt utilizate anumite tipuri de CSS atunci când setați o nouă valoare numerică. Folosind această sintaxă, multe probleme potențiale legate de tip pot fi evitate, iar codul rezultat este mai fiabil și fără erori.

Metodele get și set sunt doar un mic subset din toate metodele disponibile definite de API-ul Typed OM. Unele dintre ele includ:

  • clear : elimină toate stilurile inline
  • delete : elimină o proprietate CSS specificată și valoarea acesteia din stilurile inline
  • has : returnează un boolean dacă este setată o proprietate CSS specificată
  • append : adaugă o valoare suplimentară unei proprietăți care acceptă mai multe valori
  • etc.

Detectarea caracteristicilor

 var selectedElement = document.getElementById("example"); if(selectedElement.attributeStyleMap) { /* ... */ } if(selectedElement.computedStyleMap) { /* ... */ }

Starea specificațiilor W3C

  • Proiect de lucru: publicat pentru revizuire de către comunitate

Suport pentru browser

Google Chrome Microsoft Edge Opera Browser Firefox Safari
Sprijinit Sprijinit Sprijinit Nu sunt acceptate Suport parțial (*)

* acceptat cu „Funcțiile platformei web experimentale” sau cu alte caracteristici activate.

Sursa datelor: Houdini este încă gata?

API-ul Proprietăți și valori personalizate

API-ul CSS Properties And Values ​​permite dezvoltatorilor să extindă variabilele CSS adăugând un tip, o valoare inițială și definind moștenirea. Dezvoltatorii pot defini proprietăți personalizate CSS înregistrându-le folosind metoda registerProperty , care le spune browserelor cum să le tranziteze și să gestioneze fallback-ul în cazul unei erori.

 CSS.registerProperty({ name: "--colorPrimary", syntax: "<color>", inherits: false, initialValue: "blue", });

Această metodă acceptă un argument de intrare care este un obiect cu următoarele proprietăți:

  • name : numele proprietății personalizate
  • syntax : spune browserului cum să analizeze o proprietate personalizată. Acestea sunt valori predefinite, cum ar fi <color> , <integer> , <number> , <length> , <percentage> etc.
  • inherits : spune browserului dacă proprietatea personalizată moștenește valoarea părintelui său.
  • initialValue : indică valoarea inițială care este utilizată până când este suprascrisă și aceasta este folosită ca alternativă în cazul unei erori.

În exemplul următor, proprietatea personalizată de tip <color> este setată. Această proprietate personalizată va fi utilizată în tranziția gradientului. S-ar putea să vă gândiți că CSS actual nu acceptă tranziții pentru gradienții de fundal și ați avea dreptate. Observați cum proprietatea personalizată în sine este utilizată în transition , în loc de o proprietate de background care ar fi folosită pentru tranzițiile obișnuite background-color .

 .gradientBox { background: linear-gradient(45deg, rgba(255,255,255,1) 0%, var(--colorPrimary) 60%); transition: --colorPrimary 0.5s ease; /* ... */ } .gradientBox:hover { --colorPrimary: red /* ... */ }

Browserul nu știe cum să gestioneze tranziția cu gradient, dar știe cum să gestioneze tranzițiile de culoare, deoarece proprietatea personalizată este specificată ca tipul <color> . Pe un browser care acceptă Houdini, se va produce o tranziție de gradient atunci când elementul este plasat. Procentul de poziție a gradientului poate fi înlocuit și cu o proprietate personalizată CSS (înregistrată ca tip <percentage> ) și adăugat la o tranziție în același mod ca în exemplu.

Dacă registerProperty este eliminată și o proprietate personalizată CSS obișnuită este înregistrată într-un selector :root , tranziția gradientului nu va funcționa. Este necesar ca registerProperty să fie utilizat, astfel încât browserul să știe că ar trebui să o trateze ca culoare.

În implementarea viitoare a acestui API, ar fi posibil să înregistrați o proprietate personalizată direct în CSS.

 @property --colorPrimary { syntax: "<color>"; inherits: false; initial-value: blue; }

Exemplu

Acest exemplu simplu prezintă culoarea gradientului și tranziția poziției la evenimentul de trecere cu mouse-ul folosind proprietăți personalizate CSS înregistrate pentru culoare și, respectiv, poziție. Codul sursă complet este disponibil în exemplul de depozit.

Culoarea și poziția gradientului animate folosind API-ul Custom Properties & Values. Întârziere pentru fiecare proprietate adăugată pentru efect în proprietatea de tranziție CSS. (Previzualizare mare)

Detectarea caracteristicilor

 if (CSS.registerProperty) { /* ... */ }

Starea specificațiilor W3C

  • Proiect de lucru: publicat pentru revizuire de către comunitate

Suport pentru browser

Google Chrome Microsoft Edge Opera Browser Firefox Safari
Sprijinit Sprijinit Sprijinit Nu sunt acceptate Nu sunt acceptate

Sursa datelor: Houdini este încă gata?

API-ul Font Metrics

API-ul Font Metrics este încă într-un stadiu incipient de dezvoltare, așa că specificațiile sale se pot schimba în viitor. În versiunea sa actuală, Font Metrics API va oferi metode de măsurare a dimensiunilor elementelor de text care sunt redate pe ecran pentru a permite dezvoltatorilor să afecteze modul în care elementele de text sunt redate pe ecran. Aceste valori sunt fie dificil, fie imposibil de măsurat cu funcțiile actuale, așa că acest API va permite dezvoltatorilor să creeze mai ușor funcții CSS legate de text și fonturi. Trunchierea textului dinamic pe mai multe linii este un exemplu de una dintre aceste caracteristici.

Starea specificațiilor W3C

  • Culegere de idei: nu s-a prezentat nici un proiect de caiet de sarcini în acest moment

Suport pentru browser

Google Chrome Microsoft Edge Opera Browser Firefox Safari
Nu sunt acceptate Nu sunt acceptate Nu sunt acceptate Nu sunt acceptate Nu sunt acceptate

Sursa datelor: Houdini este încă gata?

Worklet-uri

Înainte de a trece la celelalte API-uri, este important să explicăm conceptul Worklets. Worklet -urile sunt scripturi care rulează în timpul redării și sunt independente de mediul principal JavaScript. Sunt un punct de extensie pentru motoarele de randare. Ele sunt proiectate pentru paralelism (cu 2 sau mai multe instanțe) și fire-agnostic, au acces redus la domeniul global și sunt apelate de motorul de randare atunci când este necesar. Worklet-urile pot fi rulate numai pe HTTPS (în mediul de producție) sau pe localhost (în scopuri de dezvoltare).

Houdini introduce următoarele Worklet-uri pentru a extinde motorul de randare a browserului:

  • Paint Worklet - API-ul Paint
  • Animation Worklet - Animation API
  • Layout Worklet - Layout API

Paint API

API-ul Paint le permite dezvoltatorilor să folosească funcții JavaScript pentru a desena direct în fundalul, chenarul sau conținutul unui element folosind Contextul de randare 2D, care este un subset al API-ului HTML5 Canvas. Paint API folosește Paint Worklet pentru a desena o imagine care răspunde dinamic la modificările CSS (modificări ale variabilelor CSS, de exemplu). Oricine este familiarizat cu API-ul Canvas se va simți ca acasă cu API-ul Houdini Paint.

Există mai mulți pași necesari în definirea unui set de lucru de vopsea:

  1. Scrieți și înregistrați un Paint Worklet folosind funcția registerPaint
  2. Apelați Worklet-ul în fișierul HTML sau fișierul principal JavaScript folosind funcția CSS.paintWorklet.addModule
  3. Utilizați funcția paint() în CSS cu un nume de Worklet și argumente de intrare opționale.

Să aruncăm o privire la funcția registerPaint care este folosită pentru a înregistra un Paint Worklet și pentru a-i defini funcționalitatea.

 registerPaint("paintWorketExample", class { static get inputProperties() { return ["--myVariable"]; } static get inputArguments() { return ["<color>"]; } static get contextOptions() { return {alpha: true}; } paint(ctx, size, properties, args) { /* ... */ } });

Funcția registerPaint constă din mai multe părți:

  • inputProperties :
    O serie de proprietăți personalizate CSS pe care Worklet-ul le va urmări. Această matrice reprezintă dependențele unui worklet de vopsire.
  • inputArguments :
    O serie de argumente de intrare care pot fi transmise de la funcția paint din interiorul CSS.
  • contextOptions : permite sau nu permite opacitatea culorilor. Dacă este setată la false , toate culorile vor fi afișate cu opacitate completă.
  • paint : funcția principală care oferă următoarele argumente:
    • ctx : context de desen 2D, aproape identic cu contextul de desen 2D al API-ului Canvas.
    • size : un obiect care conține lățimea și înălțimea elementului. Valorile sunt determinate de procesul de randare a aspectului. Dimensiunea pânzei este aceeași cu dimensiunea reală a elementului.
    • properties : variabilele de intrare definite în inputProperties
    • args : o serie de argumente de intrare transmise în funcția de paint în CSS

După ce Worklet-ul a fost înregistrat, acesta trebuie invocat în fișierul HTML prin simpla furnizare a unei căi către fișier.

 CSS.paintWorklet.addModule("path/to/worklet/file.js");

Orice Worklet poate fi adăugat și de la o adresă URL externă (de la o rețea de livrare de conținut, de exemplu), ceea ce le face modulare și reutilizabile.

 CSS.paintWorklet.addModule("https://url/to/worklet/file.js");

După ce Worklet-ul a fost apelat, acesta poate fi folosit în interiorul CSS folosind funcția de paint . Această funcție acceptă numele înregistrat al Worklet-ului ca prim argument de intrare și fiecare argument de intrare care îl urmează este un argument personalizat care poate fi transmis unui Worklet (definit în interiorul inputArguments al inputArguments -ului). Din acel moment, browserul determină când să apeleze Worklet-ul și la ce acțiuni ale utilizatorului și valoarea proprietăților personalizate CSS se modifică la care să răspundă.

 .exampleElement { /* paintWorkletExample - name of the worklet blue - argument passed to a Worklet */ background-image: paint(paintWorketExample, blue); }

Exemplu

Următorul exemplu prezintă API-ul Paint și reutilizarea și modularitatea generală a Worklet-urilor. Utilizează ripple Worklet direct din depozitul Google Chrome Labs și rulează pe un alt element cu stiluri diferite. Codul sursă complet este disponibil în exemplul de depozit.

Exemplu de efect de ondulare (folosește Ripple Worklet de la Google Chrome Labs) (previzualizare mare)

Detectarea caracteristicilor

 if ("paintWorklet" in CSS) { /* ... */ } @supports(background:paint(paintWorketExample)){ /* ... */ }

Starea specificațiilor W3C

  • Recomandarea candidatului: proiect de lucru stabil, gata de implementare

Suport pentru browser

Google Chrome Microsoft Edge Opera Browser Firefox Safari
Sprijinit Sprijinit Sprijinit Nu sunt acceptate Nu sunt acceptate

Sursa datelor: Houdini este încă gata?

API de animație

API-ul Animation extinde animațiile web cu opțiuni pentru a asculta diverse evenimente (defilare, trecere cu mouse-ul, clic etc.) și îmbunătățește performanța prin rularea animațiilor pe propriul fir dedicat utilizând un Animation Worklet. Permite acțiunii utilizatorului să controleze fluxul de animație care rulează într-un mod performant, neblocant.

Ca orice Worklet, Animation Worklet trebuie mai întâi înregistrat.

 registerAnimator("animationWorkletExample", class { constructor(options) { /* ... */ } animate(currentTime, effect) { /* ... */ } });

Această clasă constă din două funcții:

  • constructor : apelat când este creată o nouă instanță. Folosit pentru configurarea generală.
  • animate : funcția principală care conține logica animației. Oferă următoarele argumente de intrare:
    • currentTime : valoarea curentă a timpului din cronologia definită
    • effect : o serie de efecte pe care le folosește această animație

După ce letul de lucru de animație a fost înregistrat, acesta trebuie inclus în fișierul JavaScript principal , animația (element, cadre cheie, opțiuni) trebuie definită și animația este instanțiată cu cronologia selectată. Conceptele de cronologie și elementele de bază ale animației web vor fi explicate în secțiunea următoare.

 /* Include Animation Worklet */ await CSS.animationWorklet.addModule("path/to/worklet/file.js");; /* Select element that's going to be animated */ const elementExample = document.getElementById("elementExample"); /* Define animation (effect) */ const effectExample = new KeyframeEffect( elementExample, /* Selected element that's going to be animated */ [ /* ... */ ], /* Animation keyframes */ { /* ... */ }, /* Animation options - duration, delay, iterations, etc. */ ); /* Create new WorkletAnimation instance and run it */ new WorkletAnimation( "animationWorkletExample" /* Worklet name */ effectExample, /* Animation (effect) timeline */ document.timeline, /* Input timeline */ {}, /* Options passed to constructor */ ).play(); /* Play animation */

Maparea cronologiei

Animația web se bazează pe cronologie și maparea orei curente la o cronologie a orei locale a unui efect . De exemplu, să aruncăm o privire la o animație liniară care se repetă cu 3 cadre cheie (început, mijloc, ultimul) care rulează la 1 secundă după ce o pagină este încărcată (întârziere) și cu o durată de 4 secunde.

Cronologia efectului din exemplu ar arăta astfel (cu durata de 4 secunde fără întârziere):

Cronologia efectului (durata de 4 secunde) Cadru cheie
0 ms Primul cadru cheie - începe animația
2000 ms Cadru cheie din mijloc - animație în curs
4000 ms Ultimul cadru cheie - animația se termină sau se resetează la primul cadru cheie

Pentru a înțelege mai bine effect.localTime , prin setarea valorii sale la 3000ms (ținând cont de întârzierea de 1000ms), animația rezultată va fi blocată într-un cadru-cheie mijlociu în cronologie efectivă (întârziere 1000ms + 2000ms pentru un cadru-cheie mijlociu). Același efect se va întâmpla prin setarea valorii la 7000ms și 11000ms deoarece animația se repetă în interval de 4000ms (durata animației).

 animate(currentTime, effect) { effect.localTime = 3000; // 1000ms delay + 2000ms middle keyframe }

Nu are loc nicio animație când are un efect constant.valoare effect.localTime deoarece animația este blocată într-un cadru cheie specific. Pentru a anima corect un element, effect.localTime acestuia.localTime trebuie să fie dinamic. Este necesar ca valoarea să fie o funcție care depinde de argumentul de intrare currentTime sau de o altă variabilă.

Următorul cod arată o reprezentare funcțională a maparii 1:1 (funcție liniară) a unei linii temporale pentru a afecta ora locală.

 animate(currentTime, effect) { effect.localTime = currentTime; // y = x linear function }
Cronologie ( document.timeline ) Efect mapat ora locală Cadru cheie
startTime + 0ms (timpul scurs) startTime + 0 ms Primul
startTime + 1000 ms (timp scurs) startTime + 1000ms (întârziere) + 0ms Primul
startTime + 3000 ms (timp scurs) startTime + 1000ms (întârziere) + 2000ms Mijloc
startTime + 5000 ms (timp scurs) startTime + 1000ms (întârziere) + 4000ms Ultimul / Primul
startTime + 7000ms (timp scurs) startTime + 1000ms (întârziere) + 6000ms Mijloc
startTime + 9000ms (timp scurs) startTime + 1000ms (întârziere) + 8000ms Ultimul / Primul

Cronologia nu este limitată la maparea 1:1 la ora locală a efectului. Animation API permite dezvoltatorilor să manipuleze maparea cronologiei în funcția de animate folosind funcții JavaScript standard pentru a crea cronologie complexe. De asemenea, animația nu trebuie să se comporte la fel în fiecare iterație (dacă animația se repetă).

Animația nu trebuie să depindă de cronologia documentului, care începe doar să numere milisecunde din momentul în care este încărcată. Acțiunile utilizatorului, cum ar fi evenimentele de defilare, pot fi folosite ca cronologie pentru animație, folosind un obiect ScrollTimeline . De exemplu, o animație poate începe când un utilizator a derulat până la 200 de pixeli și se poate termina când un utilizator a derulat până la 800 de pixeli pe un ecran.

 const scrollTimelineExample = new ScrollTimeline({ scrollSource: scrollElement, /* DOM element whose scrolling action is being tracked */ orientation: "vertical", /* Scroll direction */ startScrollOffset: "200px", /* Beginning of the scroll timeline */ endScrollOffset: "800px", /* Ending of the scroll timeline */ timeRange: 1200, /* Time duration to be mapped to scroll values*/ fill: "forwards" /* Animation fill mode */ }); ...

Animația se va adapta automat la viteza de derulare a utilizatorului și va rămâne fluidă și receptivă. Deoarece Animation Worklets rulează din firul principal și sunt conectate la motorul de redare al unui browser, animația care depinde de derularea utilizatorului poate rula fără probleme și poate fi foarte performantă.

Exemplu

Următorul exemplu arată cum o implementare a cronologiei neliniare. Utilizează funcția Gaussiană modificată și aplică animație de translație și rotație cu aceeași cronologie. Codul sursă complet este disponibil în exemplul de depozit.

Animație creată cu Animation API care utilizează maparea temporală a funcției gaussiene modificate (previzualizare mare)

Detectarea caracteristicilor

 if (CSS.animationWorklet) { /* ... */ }

Starea specificațiilor W3C

  • Prima versiune publică de lucru: gata pentru revizuirea comunității, predispusă la modificarea specificațiilor

Suport pentru browser

Google Chrome Microsoft Edge Opera Browser Firefox Safari
Suport parțial (*) Suport parțial (*) Suport parțial (*) Nu sunt acceptate Nu sunt acceptate

* acceptat cu marcajul „Funcțiile platformei web experimentale” activat.

Sursa datelor: Houdini este încă gata?

Layout API

API-ul Layout permite dezvoltatorilor să extindă procesul de redare a aspectului browserului prin definirea de noi moduri de aspect care pot fi utilizate în proprietatea CSS display . Layout API introduce concepte noi, este foarte complex și oferă o mulțime de opțiuni pentru dezvoltarea algoritmilor de layout personalizați.

Similar altor worklet-uri, worklet-ul de aspect trebuie mai întâi înregistrat și definit.

 registerLayout('exampleLayout', class { static get inputProperties() { return ['--exampleVariable']; } static get childrenInputProperties() { return ['--exampleChildVariable']; } static get layoutOptions() { return { childDisplay: 'normal', sizing: 'block-like' }; } intrinsicSizes(children, edges, styleMap) { /* ... */ } layout(children, edges, constraints, styleMap, breakToken) { /* ... */ } });

Registrul de worklet conține următoarele metode:

  • inputProperties :
    O serie de proprietăți personalizate CSS pe care Worklet-ul le va ține evidența și care aparține unui element Parent Layout, adică elementului care apelează acest aspect. Această matrice reprezintă dependențe ale unui Layout Worklet.
  • childrenInputProperties :
    O serie de proprietăți personalizate CSS pe care Worklet-ul le va ține evidența și care aparțin elementelor secundare ale unui element Parent Layout, adică fiii elementelor care setează acest aspect.
  • layoutOptions : definește următoarele proprietăți de aspect:
    • childDisplay : poate avea o valoare predefinită de block sau normal . Stabilește dacă casetele vor fi afișate ca blocuri sau în linie.
    • sizing : poate avea o valoare predefinită de block-like sau manual . Spune browserului fie să precalculeze dimensiunea, fie să nu precalculeze (cu excepția cazului în care o dimensiune este setată în mod explicit).
  • intrinsicSizes : definește modul în care o casetă sau conținutul acesteia se potrivește într-un context de aspect.
    • children : elemente copil ale unui element Parent Layout, adică copiii elementului care numesc acest aspect.
    • edges : Aspect Marginile unei casete
    • styleMap : stiluri OM tastate ale unei casete
  • layout : funcția principală care realizează un layout.
    • children : elemente copil ale unui element Parent Layout, adică copiii elementului care numesc acest aspect.
    • edges : Aspect Marginile unei casete
    • constraints : constrângeri ale unui aspect părinte
    • styleMap : stiluri OM tastate ale unei casete
    • breakToken : jeton de pauză folosit pentru a relua un aspect în caz de paginare sau tipărire.

Ca și în cazul unui API Paint, motorul de randare a browserului determină când este apelat worklet-ul de vopsire. Trebuie doar adăugat la un fișier HTML sau JavaScript principal.

 CSS.layoutWorklet.addModule('path/to/worklet/file.js');

Și, în sfârșit, trebuie să fie referit într-un fișier CSS

 .exampleElement { display: layout(exampleLayout); }

Cum efectuează API-ul Layout aspectul

În exemplul anterior, exampleLayout a fost definit folosind API-ul Layout.

 .exampleElement { display: layout(exampleLayout); }

Acest element se numește Parent Layout , care este inclus cu Layout Edges , care constă din umplutură, chenare și bare de defilare. Aspectul părinte este format din elemente secundare care sunt numite Aspecte curente . Aspectele curente sunt elementele țintă reale al căror aspect poate fi personalizat folosind API-ul Layout. De exemplu, când utilizați display: flex; pe un element, copiii acestuia sunt repoziționați pentru a forma aspectul flexibil. Acest lucru este similar cu ceea ce se face cu API-ul Layout.

Fiecare Aspect curent constă din Aspect Child , care este un algoritm de aspect pentru LayoutChild (element, ::before și ::after pseudo-elemente) și LayoutChild este o casetă generată CSS care conține doar date de stil (fără date de aspect). Elementele LayoutChild sunt create automat de motorul de randare a browserului la pasul de stil. Layout Child poate genera un Fragment care realizează de fapt acțiuni de randare a aspectului.

Exemplu

Similar cu exemplul API-ului Paint, acest exemplu importă un Worklet cu aspect de zidărie direct din depozitul Google Chrome Labs, dar în acest exemplu, este folosit cu conținut de imagine în loc de text. Codul sursă complet este disponibil în exemplul de depozit.

Exemplu de aspect pentru zidărie (folosește Masonry Worklet de la Google Chrome Labs (previzualizare mare)

Detectarea caracteristicilor

 if (CSS.layoutWorklet) { /* ... */ }

Starea specificațiilor W3C

  • Prima versiune publică de lucru: gata pentru revizuirea comunității, predispusă la modificarea specificațiilor

Suport pentru browser

Google Chrome Microsoft Edge Opera Browser Firefox Safari
Suport parțial (*) Suport parțial (*) Suport parțial (*) Nu sunt acceptate Nu sunt acceptate

* acceptat cu marcajul „Funcțiile platformei web experimentale” activat.

Sursa datelor: Houdini este încă gata?

Houdini și îmbunătățirea progresivă

Chiar dacă CSS Houdini nu are încă suport optim pentru browser, acesta poate fi folosit astăzi având în vedere îmbunătățirea progresivă. Dacă nu sunteți familiarizat cu îmbunătățirea progresivă, ar merita să consultați acest articol la îndemână, care o explică foarte bine. Dacă decideți să implementați Houdini în proiectul dvs. astăzi, există câteva lucruri de reținut:

  • Utilizați funcția de detectare pentru a preveni erorile.
    Fiecare API și Worklet Houdini oferă o modalitate simplă de a verifica dacă este disponibil în browser. Utilizați funcția de detectare pentru a aplica îmbunătățirile Houdini numai browserelor care o acceptă și pentru a evita erorile.
  • Utilizați-l numai pentru prezentare și îmbunătățire vizuală.
    Utilizatorii care navighează pe un site web cu un browser care nu acceptă încă Houdini ar trebui să aibă acces la conținutul și la funcționalitatea de bază a site-ului. Experiența utilizatorului și prezentarea conținutului nu ar trebui să depindă de caracteristicile Houdini și ar trebui să aibă o rezervă de încredere.
  • Folosiți un CSS de rezervă standard.
    De exemplu, proprietățile personalizate CSS obișnuite pot fi folosite ca alternativă pentru stilurile definite folosind API-ul Custom Properties & Values.

Concentrați-vă mai întâi pe dezvoltarea unei experiențe de utilizare a site-ului web performantă și de încredere, apoi utilizați funcțiile Houdini în scopuri decorative, ca o îmbunătățire progresivă.

Concluzie

API-urile Houdini vor permite în sfârșit dezvoltatorilor să păstreze codul JavaScript folosit pentru manipularea stilului și decorarea mai aproape de canalul de randare a browserului, rezultând o performanță și o stabilitate mai bune. Permițând dezvoltatorilor să se conecteze la procesul de randare a browserului, aceștia vor putea dezvolta diverse polifillări CSS care pot fi ușor partajate, implementate și, potențial, adăugate la specificația CSS în sine. De asemenea, Houdini va face dezvoltatorii și designerii mai puțin constrânși de limitările CSS atunci când lucrează la stil, machete și animații, rezultând noi experiențe web încântătoare.

Funcțiile CSS Houdini pot fi adăugate proiectelor astăzi, dar strict având în vedere îmbunătățirea progresivă. Acest lucru va permite browserelor care nu acceptă funcțiile Houdini să redeze site-ul web fără erori și să ofere o experiență optimă pentru utilizator.

Va fi interesant să urmărim ce va veni cu comunitatea de dezvoltatori, pe măsură ce Houdini câștigă acțiune și suport mai bun pentru browser. Iată câteva exemple minunate de experimente API Houdini din comunitate:

  • Experimentele CSS Houdini
  • Introducere interactivă în CSS Houdini
  • Houdini Samples de Google Chrome Labs

Referințe

  • Proiecte de specificații W3C Houdini
  • Statul Houdini (Chrome Dev Summit 2018)
  • Houdini's Animation Worklet - Google Developers
  • Introducere interactivă în CSS Houdini