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.
Typed Object Model API
Before Houdini was introduced, the only way for JavaScript to interact with CSS was by parsing CSS represented as string values and modifying them. Parsing and overriding styles manually can be difficult and error-prone due to the value type needing to be changed back and forth and value unit needing to be manually appended when assigning a new value.
selectedElement.style.fontSize = newFontSize + "px"; // newFontSize = 20
console.log(selectedElement.style.fontSize); // "20px"
Typed Object Model (Typed OM) API adds more semantic meaning to CSS values by exposing them as typed JavaScript objects. It significantly improves the related code and makes it more performant, stable and maintainable. CSS values are represented by the CSSUnitValue interface which consists of a value and a unit property.
{
value: 20,
unit: "px"
}
This new interface can be used with the following new properties:
-
computedStyleMap()
: for parsing computed (non-inline) styles. This is a method of selected element that needs to be invoked before parsing or using other methods. -
attributeStyleMap
: for parsing and modifying inline styles. This is a property that is available on a selected element.
// 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"}
Notice how specific CSS types are being used when setting a new numeric value. By using this syntax, many potential type-related issues can be avoided and the resulting code is more reliable and bug-free.
The get
and set
methods are only a small subset of all available methods defined by the Typed OM API. Some of them include:
-
clear
: removes all inline styles -
delete
: removes a specified CSS property and its value from inline styles -
has
: returns a boolean if a specified CSS property is set -
append
: adds an additional value to a property that supports multiple values - etc.
Feature detection
var selectedElement = document.getElementById("example");
if(selectedElement.attributeStyleMap) {
/* ... */
}
if(selectedElement.computedStyleMap) {
/* ... */
}
W3C Specification Status
Working Draft: published for review by the community
Browser Support
- Microsoft Edge - Supported
- Opera Browser - Supported
- Firefox - Not supported
- Safari - Partial Support(*)
(*) supported with “Experimental Web Platform features” or other feature flag enabled.
Data source: Is Houdini Ready Yet?
Custom Properties And Values API
The CSS Properties And Values API allows developers to extend CSS variables by adding a type, initial value and define inheritance. Developers can define CSS custom properties by registering them using the registerProperty
method which tells the browsers how to transition it and handle fallback in case of an error.
CSS.registerProperty({
name: "--colorPrimary",
syntax: "<color>",
inherits: false,
initialValue: "blue",
});
This method accepts an input argument that is an object with the following properties:
-
name
: the name of the custom property -
syntax:
tells the browser how to parse a custom property. These are pre-defined values like<color>
,<integer>
,<number>
,<length>
,<percentage>
, etc. -
inherits
: tells the browser whether the custom property inherits its parent’s value. -
initialValue
: tells the initial value that is used until it’s overridden and this is used as a fallback in case of an error.
In the following example, the <color>
type custom property is being set. This custom property is going to be used in gradient transition. You might be thinking that current CSS doesn’t support transitions for background gradients and you would be correct. Notice how the custom property itself is being used in transition
, instead of a background
property that would be used for regular background-color
transitions.
.gradientBox {
background: linear-gradient(45deg, rgba(255,255,255,1) 0%, var(--colorPrimary) 60%);
transition: --colorPrimary 0.5s ease;
/* ... */
}
.gradientBox:hover {
--colorPrimary: red
/* ... */
}
Browser doesn’t know how to handle gradient transition, but it knows how to handle color transitions because the custom property is specified as <color>
type. On a browser that supports Houdini, a gradient transition will happen when the element is being hovered on. Gradient position percentage can also be replaced with CSS custom property (registered as <percentage>
type) and added to a transition in the same way as in the example.
If registerProperty
is removed and a regular CSS custom property is registered in a :root
selector, the gradient transition won’t work. It’s required that registerProperty
is used so the browser knows that it should treat it as color.
In the future implementation of this API, it would be possible to register a custom property directly in CSS.
@property --colorPrimary {
syntax: "<color>";
inherits: false;
initial-value: blue;
}
Example
This simple example showcases gradient color and position transition on hover event using registered CSS custom properties for color and position respectively. Complete source code is available on the example repository.
Feature Detection
if (CSS.registerProperty) {
/* ... */
}
W3C Specification Status
Working Draft: published for review by the community
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.
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.
Top comments (2)
Once again, amazing, and super nice to learn.
Thank you very much Sean. Glad you found it useful!