A Houdini Quickstart: registerProperty

Houdini has been discussed here and there for a few years now, always with the promise that it will open doors we have never had. Want to make a new way to do layout? Houdini. Want to create a new kind of gradient? Houdini.

In short, Houdini gives a developer building blocks in JavaScript to allow writing new kinds of CSS.

We have reached the point where this is more than just an idea or a spec. There are modules now in Blink browsers behind a flag (as of this writing, this is the only way to try it). There are many code examples, but at first glance it all seems… complicated. Some of the key examples that resources point to look like a mysterious combination of CSS Variables, Canvas drawing, and JS in CSS.

Luckily, there is a way to start exploring Houdini with one basic JavaScript method, called CSS.registerProperty(). We will look at Houdini in the context of CSS Custom Properties (CSS Variables) and animation.

See the Pen Dance of the Houdini Hexagons by Dan Wilson (@danwilson) on CodePen.

Setting the Stage: An Intro to Custom Properties

I saw the power of Custom Properties with their support independent transform properties in Firefox, Edge, Chrome, Opera, and Safari. They allows us, for example, to modify a scale without modifying an existing rotate on the same element, even though those are tied into a single transform property.

Custom Properties are powerful since they introduced a variable option to CSS natively for the first time, and they fit in with the cascade and inheritance nicely. But they, by design for the first spec, are not as powerful as they can be. To get the initial implementations in so many browsers semi-quickly, their power was limited. When you say --my-prop: 2px, the browser does not really know that is a length value. When it is used in the context of another property that expects a length (e.g. transform: translateX(var(--my-prop))), the browser then is able to parse it and treat it like a length.

Therefore, you cannot set a transition for --my-prop or modify its value in a @keyframes rule and have it animate smoothly. The browser does not have enough information to know what kind of syntax it is dealing with, or if it is even animatable. You can, however, still transition the property that it is used within if it is animatable (like the transform earlier).

Enter CSS.registerProperty() from the Properties and Values API

With the Properties and Values API spec (inside the larger Houdini endeavor) we can now tell the browser what to expect for each property.

if (window.CSS && CSS.registerProperty) {
  CSS.registerProperty({
    name: '--my-prop',
    syntax: '<length>',
    initialValue: '0px',
    inherits: false
  });
}

Here we can say that we want our CSS custom property named --my-prop to always have a valid <length> value. We also specify an initial value (for when no value is defined when we reference it via var()) and whether it inherits or not. To show the flexibility inherits provides, take the following CSS:

ul, ol {
  --my-prop: 20em;
}
li {
  width: var(--my-prop);
}

If inherits is true then the width of the list item will be 20em since it can inherit its value from an ancestor. Otherwise, a false value will mean the list items will have a width of 0px since that was the initial value defined in our JavaScript and there is no other value defined specifically on the li element.

By defining rules around how this property will behave we can have the browser reject syntaxes we do not want to support. Even more exciting (to me) is that we now have told the browser that a property is a length syntax (or angle, number, color, etc. as defined in the spec) which the browser knows how to animate.

Fancy Transforms as an example

See the Pen Animating CSS Variables (Houdini Basics) by Dan Wilson (@danwilson) on CodePen.

We register several properties in the JavaScript as angles, and then we give three nested elements each a transform that is composed of the the same custom properties in different variations of rotations. We can give them all the exact same @keyframes, but each will have a different animation since the custom properties combine into different transforms.

This extends to transitions, as well where you can specify different transitions for each of the transform functions that make up a single transform property.

But why stop there when you can even combine animations and transitions on a single transform. In this example, each element still has a keyframe animation, but on body:hover the middle element will do an additional rotation around the Z axis, smoothly performing its transition while the animation continues. The browser has all the informaiton it needs to interpolate the values thanks to the custom property’s syntax defined with CSS.registerProperty().

See the Pen Animating CSS Variables (Houdini Basics 2) by Dan Wilson (@danwilson) on CodePen.

More Info

Vincent De Oliveira has an excellent playground that shows off Houdini at a larger scale, including the other APIs under the Houdini banner like Paint and Layout. Google also is putting the initial Paint API in Chrome stable soon, with a solid introduction by Surma.

Enjoy.