DEV Community

Cover image for CSS Houdini Worklets, Paint API and Font Metrics API
Adrian Bece
Adrian Bece

Posted on • Updated on

CSS Houdini Worklets, Paint API and Font Metrics API

This post has been originally published on Smashing Magazine and I decided to split it into parts to make it more digestible. I'll be converting the post into markdown and publish a part of it on DEV every week. If you want to read it right away in its entirety, feel free to read it on Smashing Magazine until all parts are available on DEV. Thank you.


Font Metrics API

The Font Metrics API is still in a very early stage of development, so its specification may change in the future. In its current draft, Font Metrics API will provide methods for measuring dimensions of text elements that are being rendered on screen in order to allow developers to affect how text elements are being rendered on screen. These values are either difficult or impossible to measure with current features, so this API will allow developers to create text and font-related CSS features more easily. Multi-line dynamic text truncation is an example of one of those features.

W3C Specification Status

Collection of Ideas: no specification draft submitted at the moment

Browser Support

Unsupported in all browsers

Worklets

Before moving onto the other APIs, it’s important to explain the Worklets concept. Worklets are scripts that run during render and are independent of the main JavaScript environment. They are an extension point for rendering engines. They are designed for parallelism (with 2 or more instances) and thread-agnostic, have reduced access to the global scope and are called by the rendering engine when needed. Worklets can be run only on HTTPS (on production environment) or on localhost (for development purposes).

Houdini introduces following Worklets to extend the browser render engine:

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

Paint API

The Paint API allows developers to use JavaScript functions to draw directly into an element’s background, border, or content using 2D Rendering Context, which is a subset of the HTML5 Canvas API. Paint API uses Paint Worklet to draw an image that dynamically responds to changes in CSS (changes in CSS variables, for example). Anyone familiar with Canvas API will feel right at home with Houdini’s Paint API.

There are several steps required in defining a Paint Worklet:

  1. Write and register a Paint Worklet using the registerPaint function
  2. Call the Worklet in HTML file or main JavaScript file using CSS.paintWorklet.addModule function
  3. Use the paint() function in CSS with a Worklet name and optional input arguments.

Let’s take a look at the registerPaint function which is used to register a Paint Worklet and define its functionality.

registerPaint("paintWorketExample", class {
  static get inputProperties() { return ["--myVariable"]; }
  static get inputArguments() { return ["<color>"]; }
  static get contextOptions() { return {alpha: true}; }

  paint(ctx, size, properties, args) {
    /* ... */
  }
});
Enter fullscreen mode Exit fullscreen mode

The registerPaint function consists of several parts:

  • inputProperties: An array of CSS custom properties that the Worklet will keep track of. This array represents dependencies of a paint worklet.
  • inputArguments: An array of input arguments that can be passed from paint function from inside the CSS.
  • contextOptions: allow or disallow opacity for colors. If set to false, all colors will be displayed with full opacity.
  • paint: the main function that provides the following arguments:
    • ctx: 2D drawing context, almost identical to Canvas API’s 2D drawing context.
    • size: an object containing the width and height of the element. Values are determined by the layout rendering process. Canvas size is the same as the actual size of the element.
    • properties: input variables defined in inputProperties
    • args: an array of input arguments passed in paint function in CSS

After the Worklet has been registered, it needs to be invoked in the HTML file by simply providing a path to the file.

CSS.paintWorklet.addModule("path/to/worklet/file.js");
Enter fullscreen mode Exit fullscreen mode

Any Worklet can also be added from an external URL (from a Content Delivery Network, for example) which makes them modular and reusable.

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

After the Worklet has been called, it can be used inside CSS using the paint function. This function accepts the Worklet’s registered name as a first input argument and each input argument that follows it is a custom argument that can be passed to a Worklet (defined inside Worklet’s inputArguments). From that point, the browser determines when to call the Worklet and which user actions and CSS custom properties value change to respond to.

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

Example

The following example showcases Paint API and general Worklet reusability and modularity. It’s using the ripple Worklet directly from Google Chrome Labs repository and runs on a different element with different styles. Complete source code is available on the example repository.

Alt Text

Ripple effect example (uses Ripple Worklet by Google Chrome Labs)

Feature detection

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

W3C Specification Status

Candidate recommendation: stable working draft ready for implementation

Browser Support

  • Google Chrome - Supported
  • Microsoft Edge - Supported
  • Opera Browser - Supported
  • Firefox - Not supported
  • Safari - Not supported


Data source: Is Houdini Ready Yet?


These articles are fueled by coffee. So if you enjoy my work and found it useful, consider buying me a coffee! I would really appreciate it.

Buy Me A Coffee

Thank you for taking the time to read this post. Keep an eye out for the next part in the series. If you've found this useful, please give it a ❤️ or 🦄, share and comment.

Oldest comments (0)