Interfejs API CSS Paint

Nowe możliwości w Chrome 65

Interfejs CSS Paint API (nazywany również „CSS Custom Paint” lub „Worklet malarski Houdiniego”) jest domyślnie włączony od Chrome 65. Co to jest? Co można z nim zrobić? Jak to działa? Czytaj dalej, czy...

Interfejs CSS Paint API umożliwia automatyczne generowanie obrazu za każdym razem, gdy właściwość CSS oczekuje go. Właściwości takie jak background-image czy border-image są zwykle używane w połączeniu z url() do wczytywania pliku graficznego lub w przypadku wbudowanych funkcji CSS, np. linear-gradient(). Zamiast ich używać możesz teraz użyć właściwości paint(myPainter), aby odwołać się do workletu.

Pisanie Workletu malarskiego

Aby zdefiniować worklet farby o nazwie myPainter, musimy wczytać plik workletu CSS za pomocą metody CSS.paintWorklet.addModule('my-paint-worklet.js'). Możemy w nim użyć funkcji registerPaint, aby zarejestrować klasę workletu farby:

class MyPainter {
  paint(ctx, geometry, properties) {
    // ...
  }
}

registerPaint('myPainter', MyPainter);

W wywołaniu zwrotnym paint() możemy użyć właściwości ctx w taki sam sposób jak z usługi CanvasRenderingContext2D, którą znamy z usługi <canvas>. Jeśli wiesz, jak rysować w <canvas>, możesz też rysować w workletach malarskich. geometry informuje o szerokości i wysokości dostępnej odbitki na płótnie. properties Wyjaśnię to w dalszej części tego artykułu.

Na początek napiszmy szachownicę z farbą i użyjmy go jako obrazu tła elementu <textarea>. Używam pola tekstowego, ponieważ domyślnie można zmienić jego rozmiar.

<!-- index.html -->
<!doctype html>
<style>
  textarea {
    background-image: paint(checkerboard);
  }
</style>
<textarea></textarea>
<script>
  CSS.paintWorklet.addModule('checkerboard.js');
</script>
// checkerboard.js
class CheckerboardPainter {
  paint(ctx, geom, properties) {
    // Use `ctx` as if it was a normal canvas
    const colors = ['red', 'green', 'blue'];
    const size = 32;
    for(let y = 0; y < geom.height/size; y++) {
      for(let x = 0; x < geom.width/size; x++) {
        const color = colors[(x + y) % colors.length];
        ctx.beginPath();
        ctx.fillStyle = color;
        ctx.rect(x * size, y * size, size, size);
        ctx.fill();
      }
    }
  }
}

// Register our class under a specific name
registerPaint('checkerboard', CheckerboardPainter);

Jeśli zdarzyło Ci się już używać usługi <canvas>, ten kod powinien wyglądać znajomo. Tutaj możesz zobaczyć prezentację na żywo.

Obszar tekstowy ze wzorem w szachownicę jako obraz tła
Tekst w obszarze tekstowym w kształcie szachownicy jako obraz tła.

Różnica w stosunku do typowych obrazów tła polega na tym, że wzór jest ponownie narysowany na żądanie, gdy użytkownik zmieni rozmiar obszaru tekstowego. Oznacza to, że obraz tła zawsze jest dokładnie takiej wielkości, jaki musi być. Obejmuje to również kompensację w przypadku wyświetlaczy o dużej gęstości.

Brzmi fajnie, ale jest też dość statyczny. Czy mamy pisać nowy worklet za każdym razem, gdy chcemy mieć ten sam wzór, ale kwadraty o innej wielkości? Odpowiedź brzmi: nie.

Określanie parametrów Workletu

Na szczęście worklet malowania ma dostęp do innych właściwości CSS, w których wkracza dodatkowy parametr properties. Nadając klasie statyczny atrybut inputProperties, możesz subskrybować zmiany dowolnej właściwości CSS, w tym właściwości niestandardowych. Wartości będą Ci przekazywane za pomocą parametru properties.

<!-- index.html -->
<!doctype html>
<style>
  textarea {
    /* The paint worklet subscribes to changes of these custom properties. */
    --checkerboard-spacing: 10;
    --checkerboard-size: 32;
    background-image: paint(checkerboard);
  }
</style>
<textarea></textarea>
<script>
  CSS.paintWorklet.addModule('checkerboard.js');
</script>
// checkerboard.js
class CheckerboardPainter {
  // inputProperties returns a list of CSS properties that this paint function gets access to
  static get inputProperties() { return ['--checkerboard-spacing', '--checkerboard-size']; }

  paint(ctx, geom, properties) {
    // Paint worklet uses CSS Typed OM to model the input values.
    // As of now, they are mostly wrappers around strings,
    // but will be augmented to hold more accessible data over time.
    const size = parseInt(properties.get('--checkerboard-size').toString());
    const spacing = parseInt(properties.get('--checkerboard-spacing').toString());
    const colors = ['red', 'green', 'blue'];
    for(let y = 0; y < geom.height/size; y++) {
      for(let x = 0; x < geom.width/size; x++) {
        ctx.fillStyle = colors[(x + y) % colors.length];
        ctx.beginPath();
        ctx.rect(x*(size + spacing), y*(size + spacing), size, size);
        ctx.fill();
      }
    }
  }
}

registerPaint('checkerboard', CheckerboardPainter);

Teraz możemy użyć tego samego kodu do wszystkich różnych rodzajów szachownicy. Co więcej, teraz możemy otworzyć Narzędzia deweloperskie i eksperymentować z wartościami aż do znalezienia odpowiedniego modelu.

Przeglądarki, które nie obsługują Workletu malowania

W momencie pisania tego tekstu był zaimplementowany tylko w Chrome Worklet farby. Choć wszyscy dostawcy przeglądarek wskazują na pozytywne sygnały, nie ma dużych postępów. Żeby być na bieżąco, regularnie sprawdzaj temat Czy Houdini już jest gotowy?. Tymczasem używaj stopniowych ulepszeń, aby Twój kod działał nawet wtedy, gdy nie obsługuje on Workletu. Aby upewnić się, że wszystko działa zgodnie z oczekiwaniami, musisz poprawić kod w 2 miejscach: w CSS i JS.

Wykrywanie obsługi workletu farby w kodzie JS można wykryć, sprawdzając obiekt CSS: js if ('paintWorklet' in CSS) { CSS.paintWorklet.addModule('mystuff.js'); } Po stronie CSS masz 2 możliwości. Możesz używać @supports:

@supports (background: paint(id)) {
  /* ... */
}

Bardziej kompaktowa sztuczka to zastosowanie tego, że CSS unieważnia deklarację właściwości, a następnie ignoruje całą deklarację właściwości, jeśli zawiera nieznaną funkcję. Jeśli określisz właściwość 2 razy – najpierw bez workletu farby, a potem przy użyciu tego worka – uzyskasz progresywne ulepszenie:

textarea {
  background-image: linear-gradient(0, red, blue);
  background-image: paint(myGradient, red, blue);
}

W przeglądarkach z obsługą workletu malowania druga deklaracja background-image zastąpi pierwszą. W przeglądarkach bez obsługi workletu malowania druga deklaracja jest nieprawidłowa i zostanie odrzucona, pozostawiając pierwszą deklarację.

Polyfill CSS

W wielu zastosowaniach można też używać kodu CSS Paint Polyfill, który dodaje obsługę stylów CSS Custom Paint i paint Workletów w nowoczesnych przeglądarkach;

Przypadki użycia

Worklety malarskie mają wiele zastosowań. Niektóre z nich są bardziej oczywiste niż inne. Jednym z bardziej oczywistych jest użycie workletu farby do zmniejszenia rozmiaru DOM. Często są one dodawane wyłącznie w celu utworzenia ozdoby za pomocą CSS. Na przykład w Material Design Lite przycisk z efektem fali zawiera 2 dodatkowe elementy <span> do zaimplementowania samej fali. Jeśli masz dużo przycisków, możesz dodać znaczną liczbę elementów DOM i zmniejszyć wydajność na urządzeniach mobilnych. Jeśli zamiast tego wdrożysz efekt fali za pomocą workletu farby, otrzymasz 0 dodatkowych elementów i tylko 1 pracownik farby. Jest też coś, co znacznie łatwiej dostosować i dostosować do swoich potrzeb.

Kolejną zaletą korzystania z workletu farby jest to, że (w większości scenariuszy) rozwiązanie korzystające z workletu malarskiego jest niewielkie pod względem liczby bajtów. Oczywiście jest z tym wątpliwość: kod malarski będzie uruchamiany zawsze, gdy zmieni się rozmiar płótna lub którykolwiek z parametrów. Jeśli więc Twój kod jest złożony i zajmuje dużo czasu, może to być przyczyną zacięć. Chrome pracuje nad usuwaniem workletów farby z wątku głównego, dzięki czemu nawet długotrwałe te aplikacje nie wpływają na responsywność głównego wątku.

Najbardziej atrakcyjnym potencjalnym klientem jest dla mnie to, że worklet farby umożliwia wydajne polyfilling funkcji CSS, których jeszcze nie ma przeglądarka. Jednym z przykładów jest polyfill gradienty stożkowe do docelowej wersji Chrome. Inny przykład: podczas spotkania CSS ustaliliśmy, że możesz mieć wiele kolorów obramowania. Gdy spotkanie trwało jeszcze długo, mój współpracownik Ian Kilpatrick napisał kod polyfill dla tego nowego sposobu działania CSS, korzystając z workletu farby.

Myślenie niestandardowo

Gdy zapoznają się z pracą malarską, większość osób zaczyna myśleć o obrazach tła i obramowaniach. Mniej intuicyjny sposób użycia workletu malowania to mask-image nadawanie elementów DOM dowolnych kształtów. Na przykład diament:

Element DOM w kształcie rombu.
Element DOM w kształcie rombu.

mask-image pobiera obraz o rozmiarze elementu. Obszary, w których obraz maski jest przezroczysty, a element jest przezroczysty. Obszary, w których obraz maski jest nieprzezroczysty, a element nieprzezroczysty.

Teraz w Chrome

Worklet farby jest od jakiegoś czasu w Chrome Canary. W Chrome 65 jest ona domyślnie włączona. Wypróbuj nowe możliwości, jakie daje aplikacja Worklet – i pokaż nam, co udało Ci się stworzyć. Więcej inspiracji znajdziesz w kolekcji Vincenta De Oliveiry.