Praktyczny przegląd CSS Houdini

Opublikowany: 2022-03-10
Krótkie podsumowanie ↬ Houdini, termin zbiorczy dla zbioru interfejsów API przeglądarek, ma na celu wprowadzenie znaczących ulepszeń w procesie tworzenia stron internetowych i ogólnie rozwoju standardów CSS. Deweloperzy frontendu będą mogli rozszerzyć CSS o nowe funkcje za pomocą JavaScript, podłączyć się do silnika renderującego CSS i poinformować przeglądarkę, jak zastosować CSS podczas procesu renderowania. Obsługa przeglądarek Houdini poprawia się, a niektóre interfejsy API są już dostępne do użytku, więc nadszedł dobry czas, aby się z nimi zapoznać i poeksperymentować. Przyjrzymy się każdej części Houdini, obecnej obsłudze przeglądarek i zobaczymy, jak można z nich korzystać dzisiaj przy użyciu progresywnego ulepszania.

Przejście od początkowej wersji roboczej do w pełni obsługiwanej i stabilnej funkcji CSS, z której mogą korzystać programiści, zajmuje dużo czasu. Wypełnienia oparte na JavaScript mogą być używane jako substytut braku obsługi przeglądarki w celu wykorzystania nowych funkcji CSS przed ich oficjalnym zaimplementowaniem. Ale w większości przypadków są one wadliwe. Na przykład scrollsnap-polyfill jest jednym z kilku wypełniaczy, których można użyć do naprawienia niespójności obsługi przeglądarki w specyfikacji CSS Scroll Snap. Ale nawet to rozwiązanie ma pewne ograniczenia, błędy i niespójności.

Potencjalną wadą stosowania wypełniaczy jest to, że mogą one mieć negatywny wpływ na wydajność i są trudne do prawidłowego wdrożenia. Ta wada jest związana z DOM i CSSOM przeglądarki. Przeglądarka tworzy DOM (Document Object Model) ze znaczników HTML i podobnie utworzyła CSSOM (CSS Object Model) ze znaczników CSS. Te dwa drzewa obiektów są od siebie niezależne. JavaScript działa na DOM i ma bardzo ograniczony dostęp do CSSOM.

Rozwiązania JavaScript Polyfill są uruchamiane dopiero po zakończeniu początkowego cyklu renderowania, tj. po utworzeniu zarówno DOM, jak i CSSOM oraz zakończeniu ładowania dokumentu. Po tym, jak Polyfill dokona zmian w stylach w DOM (przez wstawienie ich), powoduje ponowne uruchomienie procesu renderowania i ponowne renderowanie całej strony. Negatywny wpływ na wydajność staje się jeszcze bardziej widoczny, jeśli opierają się na metodzie requestAnimationFrame lub zależą od interakcji użytkownika, takich jak zdarzenia przewijania.

Kolejną przeszkodą w tworzeniu stron internetowych są różne ograniczenia nałożone przez standardy CSS . Na przykład istnieje tylko ograniczona liczba właściwości CSS, które można animować natywnie. CSS wie, jak natywnie animować kolory, ale nie wie, jak animować gradienty. Zawsze istniała potrzeba wprowadzania innowacji i tworzenia imponujących doświadczeń internetowych, przesuwając granice pomimo ograniczeń technicznych. Dlatego programiści często skłaniają się ku używaniu mniej niż idealnych obejść lub JavaScript do implementowania bardziej zaawansowanych stylów i efektów, które nie są obecnie obsługiwane przez CSS, takich jak układ murowany, zaawansowane efekty 3D, zaawansowana animacja, płynna typografia, animowane gradienty, stylizowane elementy select itp.

Wydaje się, że specyfikacje CSS nie są w stanie sprostać różnym wymaganiom branży, takim jak większa kontrola nad animacjami, ulepszone obcinanie tekstu, lepsza opcja stylizacji elementów input i select , więcej opcji display , więcej opcji filter itp.

Jakie może być potencjalne rozwiązanie? Daj programistom natywny sposób rozszerzania CSS przy użyciu różnych interfejsów API . W tym artykule przyjrzymy się, jak programiści frontend mogą to zrobić za pomocą API Houdini, JavaScript i CSS. W każdej sekcji przyjrzymy się każdemu API z osobna, sprawdzimy jego obsługę przeglądarek i aktualny stan specyfikacji oraz zobaczymy, jak można je zaimplementować już dziś przy użyciu ulepszeń Progressive.

Więcej po skoku! Kontynuuj czytanie poniżej ↓

Co to jest Houdini?

Houdini, ogólny termin określający zbiór interfejsów API przeglądarki, ma na celu wprowadzenie znaczących ulepszeń w procesie tworzenia stron internetowych i ogólnie w opracowywaniu standardów CSS. Programiści będą mogli rozszerzyć CSS o nowe funkcje za pomocą JavaScript, podłączyć się do silnika renderującego CSS i poinformować przeglądarkę, jak zastosować CSS podczas procesu renderowania. Spowoduje to znacznie lepszą wydajność i stabilność niż przy użyciu zwykłych wypełniaczy.

Specyfikacja Houdini składa się z dwóch grup API — API wysokiego poziomu i API niskiego poziomu .

API wysokiego poziomu są ściśle powiązane z procesem renderowania przeglądarki (styl → układ → malowanie → kompozyt). To zawiera:

  • Malowanie API
    Punkt rozszerzenia dla etapu renderowania malowania przeglądarki, w którym określane są właściwości wizualne (kolor, tło, obramowanie itp.).
  • Interfejs API układu
    Punkt rozszerzenia dla etapu renderowania układu przeglądarki, w którym określane są wymiary, położenie i wyrównanie elementu.
  • Interfejs API animacji
    Punkt rozszerzenia dla etapu renderowania kompozytowego przeglądarki, w którym warstwy są rysowane na ekranie i animowane.

Interfejsy API niskiego poziomu stanowią podstawę dla interfejsów API wysokiego poziomu. To zawiera:

  • Wpisany model obiektowy API
  • Interfejs API właściwości i wartości niestandardowych
  • Interfejs API metryk czcionek
  • Worklety

Niektóre interfejsy API Houdini są już dostępne do użycia w niektórych przeglądarkach z innymi interfejsami API, gdy będą gotowe do wydania.

Przyszłość CSS

W przeciwieństwie do standardowych specyfikacji funkcji CSS, które zostały wprowadzone do tej pory, Houdini wyróżnia się tym, że umożliwia programistom rozszerzanie CSS w bardziej natywny sposób. Czy to oznacza, że ​​specyfikacje CSS przestaną ewoluować i żadne nowe oficjalne implementacje funkcji CSS nie zostaną opublikowane? Cóż, tak nie jest. Celem Houdini jest wspomaganie procesu rozwoju funkcji CSS poprzez umożliwienie programistom tworzenie działających prototypów, które można łatwo standaryzować.

Ponadto programiści będą mogli łatwiej udostępniać arkusze CSS o otwartym kodzie źródłowym i redukować potrzebę naprawiania błędów w poszczególnych przeglądarkach.

Wpisany model obiektowy API

Przed wprowadzeniem Houdini jedynym sposobem interakcji JavaScript z CSS było parsowanie CSS reprezentowanych jako wartości ciągów i ich modyfikowanie. Ręczne analizowanie i zastępowanie stylów może być trudne i podatne na błędy, ponieważ typ wartości musi być zmieniany tam iz powrotem, a jednostka wartości musi być ręcznie dołączona podczas przypisywania nowej wartości.

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

Typed Object Model (Typed OM) API dodaje więcej semantycznego znaczenia do wartości CSS, eksponując je jako typowane obiekty JavaScript. Znacznie poprawia powiązany kod i czyni go bardziej wydajnym, stabilnym i łatwiejszym w utrzymaniu. Wartości CSS są reprezentowane przez interfejs CSSUnitValue , który składa się z wartości i właściwości jednostki.

 { value: 20, unit: "px" }

Ten nowy interfejs może być używany z następującymi nowymi właściwościami:

  • computedStyleMap() : do analizowania stylów obliczonych (nie wbudowanych). Jest to metoda wybranego elementu, którą należy wywołać przed parsowaniem lub użyciem innych metod.
  • attributeStyleMap : do analizowania i modyfikowania stylów wbudowanych. Jest to właściwość dostępna dla wybranego elementu.
 // 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"}

Zwróć uwagę, jak określone typy CSS są używane podczas ustawiania nowej wartości liczbowej. Używając tej składni, można uniknąć wielu potencjalnych problemów związanych z typem, a wynikowy kod jest bardziej niezawodny i wolny od błędów.

Metody get i set stanowią tylko niewielki podzbiór wszystkich dostępnych metod zdefiniowanych przez typed OM API. Niektóre z nich to:

  • clear : usuwa wszystkie style wbudowane
  • delete : usuwa określoną właściwość CSS i jej wartość ze stylów wbudowanych
  • has : zwraca wartość logiczną, jeśli określona właściwość CSS jest ustawiona
  • append : dodaje dodatkową wartość do właściwości, która obsługuje wiele wartości
  • itp.

Wykrywanie funkcji

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

Stan specyfikacji W3C

  • Wersja robocza: opublikowana do przeglądu przez społeczność

Obsługa przeglądarki

Google Chrome Microsoft Edge Przeglądarka Opera Firefox Safari
Utrzymany Utrzymany Utrzymany Niewspierany Częściowe wsparcie (*)

* obsługiwane z włączonymi „Eksperymentalnymi funkcjami platformy internetowej” lub innymi włączonymi flagami funkcji.

Źródło danych: Czy Houdini jest już gotowy?

Interfejs API właściwości i wartości niestandardowych

Interfejs API właściwości i wartości CSS umożliwia programistom rozszerzenie zmiennych CSS poprzez dodanie typu, wartości początkowej i zdefiniowanie dziedziczenia. Deweloperzy mogą definiować niestandardowe właściwości CSS, rejestrując je za pomocą metody registerProperty , która mówi przeglądarkom, jak je przenosić i obsługiwać w przypadku błędu.

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

Ta metoda akceptuje argument wejściowy, który jest obiektem o następujących właściwościach:

  • name : nazwa niestandardowej właściwości
  • syntax : informuje przeglądarkę, jak przeanalizować niestandardową właściwość. Są to wstępnie zdefiniowane wartości, takie jak <color> , <integer> , <number> , <length> , <percentage> , itp.
  • inherits : informuje przeglądarkę, czy właściwość niestandardowa dziedziczy wartość swojego rodzica.
  • initialValue : informuje o początkowej wartości, która jest używana, dopóki nie zostanie zastąpiona i jest używana jako rezerwa w przypadku błędu.

W poniższym przykładzie ustawiana jest niestandardowa właściwość <color> type. Ta niestandardowa właściwość będzie używana w przejściu gradientowym. Być może myślisz, że obecny CSS nie obsługuje przejść dla gradientów tła i miałbyś rację. Zwróć uwagę, że sama właściwość niestandardowa jest używana w funkcji transition , a nie właściwość background , która byłaby używana do zwykłych przejść 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 /* ... */ }

Przeglądarka nie wie, jak obsługiwać przejścia gradientowe, ale wie, jak obsługiwać przejścia kolorów, ponieważ właściwość niestandardowa jest określona jako typ <color> . W przeglądarce obsługującej Houdini przejście gradientowe nastąpi po najechaniu na element. Procent pozycji gradientu można również zastąpić niestandardową właściwością CSS (zarejestrowaną jako typ <percentage> ) i dodać do przejścia w taki sam sposób, jak w przykładzie.

Jeśli registerProperty zostanie usunięty, a zwykła niestandardowa właściwość CSS jest zarejestrowana w selektorze :root , przejście gradientowe nie zadziała. Wymagane jest użycie registerProperty , aby przeglądarka wiedziała, że ​​powinna traktować to jako kolor.

W przyszłej implementacji tego API możliwe byłoby zarejestrowanie niestandardowej właściwości bezpośrednio w CSS.

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

Przykład

Ten prosty przykład ilustruje przejście koloru gradientu i położenia w zdarzeniu najechania kursorem przy użyciu zarejestrowanych niestandardowych właściwości CSS odpowiednio dla koloru i położenia. Pełny kod źródłowy jest dostępny w przykładowym repozytorium.

Animowany kolor i położenie gradientu przy użyciu interfejsu API właściwości i wartości niestandardowych. Opóźnienie dla każdej dodanej właściwości dla efektu we właściwości przejścia CSS. (duży podgląd)

Wykrywanie funkcji

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

Stan specyfikacji W3C

  • Wersja robocza: opublikowana do przeglądu przez społeczność

Obsługa przeglądarki

Google Chrome Microsoft Edge Przeglądarka Opera Firefox Safari
Utrzymany Utrzymany Utrzymany Niewspierany Niewspierany

Źródło danych: Czy Houdini jest już gotowy?

Interfejs API metryk czcionek

API Font Metrics jest wciąż na bardzo wczesnym etapie rozwoju, więc jego specyfikacja może ulec zmianie w przyszłości. W obecnej wersji interfejs API Font Metrics zapewni metody mierzenia wymiarów elementów tekstowych, które są renderowane na ekranie, aby umożliwić programistom wpływanie na sposób renderowania elementów tekstowych na ekranie. Wartości te są albo trudne, albo niemożliwe do zmierzenia za pomocą obecnych funkcji, więc ten interfejs API umożliwi programistom łatwiejsze tworzenie funkcji CSS związanych z tekstem i czcionkami. Przykładem jednej z tych funkcji jest dynamiczne obcinanie tekstu wielowierszowego.

Stan specyfikacji W3C

  • Zbiór pomysłów: w tej chwili nie przedłożono projektu specyfikacji

Obsługa przeglądarki

Google Chrome Microsoft Edge Przeglądarka Opera Firefox Safari
Niewspierany Niewspierany Niewspierany Niewspierany Niewspierany

Źródło danych: Czy Houdini jest już gotowy?

Worklety

Przed przejściem do innych interfejsów API ważne jest wyjaśnienie koncepcji Worklets. Worklety to skrypty, które działają podczas renderowania i są niezależne od głównego środowiska JavaScript. Stanowią rozszerzenie dla silników renderujących. Zostały zaprojektowane z myślą o równoległości (z 2 lub więcej instancjami) i niezależnym od wątków, mają ograniczony dostęp do zakresu globalnego i są wywoływane przez silnik renderujący w razie potrzeby. Worklety można uruchamiać tylko na HTTPS (w środowisku produkcyjnym) lub na lokalnym hoście (w celach programistycznych).

Houdini wprowadza następujące Worklety rozszerzające silnik renderowania przeglądarki:

  • Paint Worklet - Paint API
  • Worklet animacji — interfejs API animacji
  • Arkusz układu — interfejs API układu

Malowanie API

Paint API umożliwia programistom używanie funkcji JavaScript do rysowania bezpośrednio w tle, obramowaniu lub zawartości elementu za pomocą kontekstu renderowania 2D, który jest podzbiorem interfejsu API HTML5 Canvas. Paint API używa Paint Worklet do rysowania obrazu, który dynamicznie reaguje na zmiany w CSS (na przykład zmiany w zmiennych CSS). Każdy, kto zna Canvas API, poczuje się jak w domu dzięki API Paint API firmy Houdini.

Istnieje kilka kroków wymaganych do zdefiniowania zadania do malowania:

  1. Napisz i zarejestruj zadanie malowania za pomocą funkcji registerPaint
  2. Wywołaj Worklet w pliku HTML lub głównym pliku JavaScript za pomocą funkcji CSS.paintWorklet.addModule
  3. Użyj funkcji paint() w CSS z nazwą Worklet i opcjonalnymi argumentami wejściowymi.

Przyjrzyjmy się funkcji registerPaint , która służy do rejestrowania Worklet Paint i definiowania jego funkcjonalności.

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

Funkcja registerPaint składa się z kilku części:

  • inputProperties :
    Tablica niestandardowych właściwości CSS, które Worklet będzie śledzić. Ta tablica reprezentuje zależności zadania malowania.
  • inputArguments :
    Tablica argumentów wejściowych, które mogą być przekazywane z funkcji paint z wnętrza CSS.
  • contextOptions : zezwalaj lub nie zezwalaj na krycie kolorów. Jeśli ustawiono na false , wszystkie kolory będą wyświetlane z pełnym kryciem.
  • paint : główna funkcja udostępniająca następujące argumenty:
    • ctx : kontekst rysowania 2D, prawie identyczny z kontekstem rysowania 2D interfejsu API Canvas.
    • size : obiekt zawierający szerokość i wysokość elementu. Wartości są określane przez proces renderowania układu. Rozmiar płótna jest taki sam jak rzeczywisty rozmiar elementu.
    • properties : zmienne wejściowe zdefiniowane w inputProperties
    • args : tablica argumentów wejściowych przekazanych w funkcji paint w CSS

Po zarejestrowaniu Worklet należy go wywołać w pliku HTML, po prostu podając ścieżkę do pliku.

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

Dowolny Worklet można również dodać z zewnętrznego adresu URL (na przykład z sieci dostarczania treści), co czyni je modułowymi i wielokrotnego użytku.

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

Po wywołaniu Worklet można go używać w CSS za pomocą funkcji paint . Ta funkcja akceptuje zarejestrowaną nazwę Workleta jako pierwszy argument wejściowy, a każdy następujący argument wejściowy jest argumentem niestandardowym, który można przekazać do Workleta (zdefiniowanego wewnątrz inputArguments inputArguments ). Od tego momentu przeglądarka określa, kiedy należy wywołać Worklet i na które akcje użytkownika i niestandardowe właściwości CSS mają się zmienić, aby odpowiedzieć.

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

Przykład

Poniższy przykład przedstawia interfejs API Paint i ogólną możliwość ponownego wykorzystania i modułowość Worklet. Korzysta z ripple Worklet bezpośrednio z repozytorium Google Chrome Labs i działa na innym elemencie z różnymi stylami. Pełny kod źródłowy jest dostępny w przykładowym repozytorium.

Przykład efektu Ripple (wykorzystuje Ripple Worklet firmy Google Chrome Labs) (duży podgląd)

Wykrywanie funkcji

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

Stan specyfikacji W3C

  • Rekomendacja kandydata: stabilny projekt roboczy gotowy do wdrożenia

Obsługa przeglądarki

Google Chrome Microsoft Edge Przeglądarka Opera Firefox Safari
Utrzymany Utrzymany Utrzymany Niewspierany Niewspierany

Źródło danych: Czy Houdini jest już gotowy?

Interfejs API animacji

Interfejs API animacji rozszerza animacje internetowe o opcje nasłuchiwania różnych zdarzeń (przewijanie, najeżdżanie, klikanie itp.) i poprawia wydajność, uruchamiając animacje we własnym dedykowanym wątku za pomocą zadania animacji. Pozwala na działanie użytkownika w celu kontrolowania przepływu animacji, która działa w wydajny, nieblokujący sposób.

Jak każdy Worklet, Worklet Animacja musi być najpierw zarejestrowany.

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

Ta klasa składa się z dwóch funkcji:

  • constructor : wywoływany, gdy tworzona jest nowa instancja. Używany do ogólnej konfiguracji.
  • animate : główna funkcja zawierająca logikę animacji. Udostępnia następujące argumenty wejściowe:
    • currentTime : aktualna wartość czasu ze zdefiniowanej osi czasu
    • effect : tablica efektów, których używa ta animacja

Po zarejestrowaniu zadania animacji należy go umieścić w głównym pliku JavaScript , zdefiniować animację (element, klatki kluczowe, opcje) i utworzyć instancję animacji z wybraną osią czasu. Koncepcje osi czasu i podstawy animacji internetowych zostaną wyjaśnione w następnej sekcji.

 /* 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 */

Mapowanie osi czasu

Animacja internetowa opiera się na osiach czasu i odwzorowaniu czasu bieżącego na oś czasu czasu lokalnego efektu . Spójrzmy na przykład na powtarzającą się animację liniową z 3 klatkami kluczowymi (początek, środek, ostatni), która jest uruchamiana 1 sekundę po załadowaniu strony (opóźnienie) i trwa 4 sekundy.

Oś czasu efektu z przykładu wyglądałaby tak (z 4-sekundowym czasem trwania bez opóźnienia):

Oś czasu efektu (czas trwania 4 s) Klatka kluczowa
0ms Pierwsza klatka kluczowa — rozpoczyna się animacja
2000ms Środkowa klatka kluczowa — trwa animacja
4000ms Ostatnia klatka kluczowa — animacja kończy się lub resetuje do pierwszej klatki kluczowej

Aby lepiej zrozumieć effect.localTime , ustawiając jego wartość na 3000ms (z uwzględnieniem opóźnienia 1000ms), wynikowa animacja zostanie zablokowana w środkowej klatce kluczowej na osi czasu efektu (opóźnienie 1000ms + 2000ms dla środkowej klatki kluczowej). Ten sam efekt wystąpi po ustawieniu wartości na 7000ms i 11000ms, ponieważ animacja powtarza się w odstępach 4000ms (czas trwania animacji).

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

Żadna animacja nie występuje, gdy ma stałą wartość effect.localTime , ponieważ animacja jest zablokowana w określonej klatce kluczowej. Aby poprawnie animować element, jego effect.localTime musi być dynamiczny. Wymagane jest, aby wartość była funkcją zależną od argumentu wejściowego currentTime lub innej zmiennej.

Poniższy kod przedstawia funkcjonalną reprezentację odwzorowania 1:1 (funkcja liniowa) osi czasu w celu wpłynięcia na czas lokalny.

 animate(currentTime, effect) { effect.localTime = currentTime; // y = x linear function }
Oś czasu ( document.timeline ) Zmapowany efekt czasu lokalnego Klatka kluczowa
startTime + 0ms (czas, który upłynął) czas startu + startTime Pierwszy
startTime + 1000ms (czas, który upłynął) startTime + 1000ms (opóźnienie) + 0ms Pierwszy
startTime + 3000ms (czas, który upłynął) startTime + 1000ms (opóźnienie) + 2000ms Środkowy
startTime + 5000ms (czas, który upłynął) startTime + 1000ms (opóźnienie) + 4000ms Ostatni pierwszy
startTime + 7000ms (czas, który upłynął) startTime + 1000ms (opóźnienie) + 6000ms Środkowy
startTime + 9000ms (czas, który upłynął) startTime + 1000ms (opóźnienie) + 8000ms Ostatni pierwszy

Oś czasu nie jest ograniczona do mapowania 1:1 na czas lokalny efektu. Interfejs API animacji umożliwia programistom manipulowanie mapowaniem osi czasu w funkcji animate za pomocą standardowych funkcji JavaScript do tworzenia złożonych osi czasu. Animacja również nie musi zachowywać się tak samo w każdej iteracji (jeśli animacja się powtarza).

Animacja nie musi zależeć od osi czasu dokumentu, która zaczyna odliczać milisekundy od momentu załadowania. Akcje użytkownika, takie jak zdarzenia przewijania, mogą być używane jako oś czasu animacji przy użyciu obiektu ScrollTimeline . Na przykład animacja może rozpocząć się, gdy użytkownik przewinie ekran do 200 pikseli, a zakończyć, gdy użytkownik przewinie ekran do 800 pikseli.

 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 */ }); ...

Animacja automatycznie dostosuje się do szybkości przewijania przez użytkownika i pozostanie płynna i responsywna. Ponieważ zadania animacji działają poza głównym wątkiem i są połączone z silnikiem renderującym przeglądarki, animacja zależna od przewijania przez użytkownika może przebiegać płynnie i być bardzo wydajna.

Przykład

Poniższy przykład ilustruje nieliniową implementację osi czasu. Wykorzystuje zmodyfikowaną funkcję Gaussa i stosuje animację przesunięcia i obrotu na tej samej osi czasu. Pełny kod źródłowy jest dostępny w przykładowym repozytorium.

Animacja utworzona za pomocą Animation API, która wykorzystuje zmodyfikowane mapowanie czasu funkcji Gaussa (duży podgląd)

Wykrywanie funkcji

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

Stan specyfikacji W3C

  • Pierwsza publiczna wersja robocza: gotowa do przeglądu przez społeczność, podatna na zmiany specyfikacji

Obsługa przeglądarki

Google Chrome Microsoft Edge Przeglądarka Opera Firefox Safari
Częściowe wsparcie (*) Częściowe wsparcie (*) Częściowe wsparcie (*) Niewspierany Niewspierany

* obsługiwane z włączoną flagą „Eksperymentalne funkcje platformy internetowej”.

Źródło danych: Czy Houdini jest już gotowy?

Interfejs API układu

Interfejs API układu umożliwia programistom rozszerzenie procesu renderowania układu przeglądarki poprzez zdefiniowanie nowych trybów układu, których można użyć we właściwości display CSS. Layout API wprowadza nowe koncepcje, jest bardzo złożony i oferuje wiele opcji tworzenia niestandardowych algorytmów układu.

Podobnie jak w przypadku innych Workletów, układ Worklet należy najpierw zarejestrować i zdefiniować.

 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) { /* ... */ } });

Rejestr zadań zawiera następujące metody:

  • inputProperties :
    Tablica niestandardowych właściwości CSS, które Worklet będzie śledzić i które należą do elementu Parent Layout, tj. elementu, który wywołuje ten układ. Ta tablica reprezentuje zależności Worklet Layout.
  • childrenInputProperties :
    Tablica niestandardowych właściwości CSS, które Worklet będzie śledzić i które należą do elementów potomnych elementu Parent Layout, tj. dzieci elementów, które ustawiają ten układ.
  • layoutOptions : definiuje następujące właściwości układu:
    • childDisplay : może mieć wstępnie zdefiniowaną wartość block lub normal . Określa, czy pola będą wyświetlane jako bloki, czy w wierszu.
    • sizing : może mieć wstępnie zdefiniowaną wartość block-like lub manual . Mówi przeglądarce, aby odpowiednio wstępnie obliczyła rozmiar lub nie obliczała wcześniej (chyba że rozmiar jest jawnie ustawiony).
  • intrinsicSizes : określa sposób dopasowania pudełka lub jego zawartości do kontekstu układu.
    • children : elementy potomne elementu Parent Layout, tj. dzieci elementu, który wywołuje ten layout.
    • edges : Układ Krawędzie pudełka
    • styleMap : wpisane style OM pola
  • layout : główna funkcja, która wykonuje układ.
    • children : elementy potomne elementu Parent Layout, tj. dzieci elementu, który wywołuje ten layout.
    • edges : Układ Krawędzie pudełka
    • constraints : ograniczenia układu nadrzędnego
    • styleMap : wpisane style OM pola
    • breakToken : przerwany token używany do wznowienia układu w przypadku paginacji lub drukowania.

Podobnie jak w przypadku Paint API, silnik renderujący w przeglądarce określa, kiedy wywoływany jest Paint Worklet. Wystarczy go dodać do pliku HTML lub głównego pliku JavaScript.

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

I na koniec, należy się do niego odnieść w pliku CSS

 .exampleElement { display: layout(exampleLayout); }

Jak interfejs API układu wykonuje układ

W poprzednim przykładzie exampleLayout został zdefiniowany przy użyciu interfejsu Layout API.

 .exampleElement { display: layout(exampleLayout); }

Ten element nazywa się Układem nadrzędnym , który jest otoczony krawędziami układu , które składają się z dopełnień, obramowań i pasków przewijania. Układ nadrzędny składa się z elementów podrzędnych, które są nazywane bieżącymi układami . Bieżące układy to rzeczywiste elementy docelowe, których układ można dostosować za pomocą interfejsu Layout API. Na przykład przy użyciu display: flex; na elemencie, jego elementy potomne są zmieniane w celu utworzenia układu elastycznego. Przypomina to działanie interfejsu Layout API.

Każdy bieżący układ składa się z układu podrzędnego , który jest algorytmem układu dla pseudoelementów LayoutChild (element, ::before i ::after ), a LayoutChild to pole wygenerowane przez CSS, które zawiera tylko dane dotyczące stylu (bez danych układu). Elementy LayoutChild są tworzone automatycznie przez silnik renderujący w przeglądarce na etapie stylu. Layout Child może wygenerować fragment , który faktycznie wykonuje akcje renderowania układu.

Przykład

Podobnie jak w przykładzie Paint API, ten przykład importuje układ masonry Worklet bezpośrednio z repozytorium Google Chrome Labs, ale w tym przykładzie jest używany z zawartością obrazu zamiast tekstu. Pełny kod źródłowy jest dostępny w przykładowym repozytorium.

Przykład układu masonry (wykorzystuje Masonry Worklet firmy Google Chrome Labs (duży podgląd)

Wykrywanie funkcji

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

Stan specyfikacji W3C

  • Pierwsza publiczna wersja robocza: gotowa do przeglądu przez społeczność, podatna na zmiany specyfikacji

Obsługa przeglądarki

Google Chrome Microsoft Edge Przeglądarka Opera Firefox Safari
Częściowe wsparcie (*) Częściowe wsparcie (*) Częściowe wsparcie (*) Niewspierany Niewspierany

* obsługiwane z włączoną flagą „Eksperymentalne funkcje platformy internetowej”.

Źródło danych: Czy Houdini jest już gotowy?

Houdini i progresywne ulepszanie

Mimo że CSS Houdini nie ma jeszcze optymalnej obsługi przeglądarek, może być dziś używany z myślą o progresywnym ulepszaniu. Jeśli nie jesteś zaznajomiony z ulepszeniem progresywnym, warto zapoznać się z tym przydatnym artykułem, który naprawdę dobrze to wyjaśnia. Jeśli już dziś zdecydujesz się na wdrożenie Houdini w swoim projekcie, pamiętaj o kilku rzeczach:

  • Użyj wykrywania funkcji, aby zapobiec błędom.
    Każde API i Worklet Houdini oferuje prosty sposób sprawdzenia, czy jest dostępny w przeglądarce. Użyj wykrywania funkcji, aby zastosować ulepszenia Houdini tylko w przeglądarkach, które je obsługują i uniknąć błędów.
  • Używaj go tylko do prezentacji i ulepszania wizualnego.
    Użytkownicy przeglądający witrynę internetową w przeglądarce, która jeszcze nie obsługuje Houdini, powinni mieć dostęp do zawartości i podstawowych funkcji witryny. Doświadczenie użytkownika i prezentacja treści nie powinny zależeć od funkcji Houdini i powinny mieć niezawodne rozwiązanie awaryjne.
  • Skorzystaj ze standardowej rezerwy CSS.
    Na przykład zwykłe niestandardowe właściwości CSS mogą być używane jako rezerwa dla stylów zdefiniowanych za pomocą interfejsu API właściwości i wartości niestandardowych.

Skoncentruj się najpierw na opracowaniu wydajnej i niezawodnej obsługi witryny, a następnie użyj funkcji Houdini do celów dekoracyjnych jako progresywnego ulepszenia.

Wniosek

Interfejsy API Houdini w końcu umożliwią programistom utrzymywanie kodu JavaScript używanego do manipulacji stylami i dekoracji bliżej potoku renderowania przeglądarki, co zapewnia lepszą wydajność i stabilność. Pozwalając programistom na podłączenie się do procesu renderowania przeglądarki, będą mogli opracować różne wypełniacze CSS, które można łatwo udostępniać, implementować i potencjalnie dodawać do samej specyfikacji CSS. Houdini sprawi również, że programiści i projektanci będą mniej ograniczeni ograniczeniami CSS podczas pracy nad stylami, układami i animacjami, co zaowocuje nowymi wspaniałymi doświadczeniami internetowymi.

Funkcje CSS Houdini można obecnie dodawać do projektów, ale ściśle z myślą o progresywnym ulepszaniu. Umożliwi to przeglądarkom, które nie obsługują funkcji Houdini, renderowanie witryny bez błędów i zapewnia optymalne wrażenia użytkownika.

To będzie ekscytujące obserwować, co wymyśli społeczność programistów, gdy Houdini zyskuje na popularności i lepszej obsłudze przeglądarek. Oto kilka niesamowitych przykładów eksperymentów Houdini API od społeczności:

  • Eksperymenty CSS Houdini
  • Interaktywne wprowadzenie do CSS Houdini
  • Próbki Houdini od Google Chrome Labs

Bibliografia

  • Szkice specyfikacji W3C Houdini
  • Stan Houdini (Chrome Dev Summit 2018)
  • Houdini's Animation Worklet – Google Developers
  • Interaktywne wprowadzenie do CSS Houdini