CSS Typed Object Model
The CSS Typed Object Model is part of the Houdini APIs. It allows the manipulation of CSS styles through objects, reducing the number of strings and strings concatenations required. This can lead to improved performance, lower memory cost and less time spent on GC, especially when used with properties requiring lots of string concatenation like transform.
Supported subset
Section titled “Supported subset”Currently Gameface supports the following parts of the CSSTOM draft:
StylePropertyMap- With the following functions -set,get,delete,clear,has.- Not supported for SVG elements.
CSSStyleValue.parseCSSKeywordValueCSSUnitValueCSSTransformValuewith itsCSSTransformComponentmembers:CSSTranslate,CSSScale,CSSRotate,CSSSkewX,CSSSkewY.
Since most of the performance of using the CSSTOM is limited to transform and the properties that use CSSUnitValue, here is the list of properties that are supported and can be a CSSUnitValue:
-
border-bottom-width -
border-left-width -
border-right-width -
border-top-width -
bottom -
flex-basis -
flex-grow -
flex-shrink -
font-size -
height -
left -
letter-spacing -
line-height -
margin-bottom -
margin-left -
margin-right -
margin-top -
max-height -
max-width -
min-height -
min-width -
opacity -
padding-bottom -
padding-left -
padding-right -
padding-top -
right -
text-decoration-thickness -
text-stroke-width -
text-underline-offset -
top -
width -
z-index -
Shorthands and custom properties are NOT currently supported with CSSTOM.
Using the CSS Typed Object Model
Section titled “Using the CSS Typed Object Model”- Example on CSSTOM usage with
CSSUnitValueobject that can be reused to set properties of multiple elements.
let width = CSSStyleValue.parse("width", "100px"); // Creates CSSUnitValue that internally is a parsed width // This saves parsing on every set...width.value = newValue[0]; // Change only a number. No creating new string and string concatenation involved.elementsAttributeStyleMaps[0].set("width", width); // We have saved the attributeStyleMaps previously. // so we don't recreate them on every setwidth.value = newValue[1]; // Reuse the object - only 1 per property is enoughelementsAttributeStyleMaps[1].set("width", width);...StylePropertyMapcontains the inline styles of the element. We get access to it by callingattributeStyleMapon an element.
So we can manipulate the inline styles in the following manner:
<div style="width: 100px;"> </div>
...let attributeStyleMap = element.attributeStyleMap;
let width = attributeStyleMap.get("width");console.log(width.value); // 100console.log(width.unit); // "px"attributeStyleMap.delete("width");attributeStyleMap.has("width"); // false
attributeStyleMap.set("height", CSS.vw(100));console.log(attributeStyleMap.get("height").value); // 100;attributeStyleMap.clear();attributeStyleMap.has("height"); // false- The place where CSSTOM really shines is when you need to update a transformation of multiple elements on the screen very often.
Here is an example of how to do that in a convenient and efficient manner with CSSTOM.
// This creates our `CSSTransform` object, parsing here is fine since we will do it only oncelet transform = CSSStyleValue.parse("transform", "translate(20px, 100px) scale(1, 2) rotate(15deg)");let elements = document.querySelectorAll(".ElementsThatTransformFrequently");let attributeStyleMaps = [];
// Save the attributeStyleMaps that will get reused often for significantly improved performancefor(let i = 0; i < elements.length; i++) attributeStyleMaps.push(elements[i].attributeStyleMap);
// updateValues contains just floats of the new values that we are going to setfunction UpdateFunction(updateValues) { for(let i = 0; i < attributeStyleMaps.length; i++) { // This would require 10 string concatenations if done with regular CSSOM transform[0].x.value = updateValues[i][0]; transform[0].y.value = updateValues[i][1]; transform[1].x.value = updateValues[i][2]; transform[1].y.value = updateValues[i][3]; transform[2].angle.value = updateValues[i][4]; attributeStyleMaps[i].set("transform", transform); }}Common pitfalls when using CSS Typed Object Model
Section titled “Common pitfalls when using CSS Typed Object Model”- Not saving the
attributeStyleMaps.
// Preferlet attributeStyleMaps = [];for(let i = 0; i < elements.length; i++) attributeStyleMaps.push(elements[i].attributeStyleMap);...function UpdateStylesOften() { ... attributeStyleMaps[i].set("someProp", somePropValue); ...}// AVOIDfunction UpdateStylesOften() { ... elements[i].attributeStyleMaps.set("someProp", somePropValue); ...}- Creating new CSSTOM objects on every update, instead of reusing CSSTOM objects and only setting their values
// AVOIDfunction UpdateStylesOften() { ... elementMaps[i].set("top", CSS.px(150)); elementMaps[i].set("left", CSS.px(50)); elementMaps[i].set("transform", new CSSTransformValue([new CSSScale(2,3)])); ...}- Having 1 CSSTOM object for DIFFERENT properties.
// AVOIDlet unitValueObj = CSSStyleValue.parse("width", CSS.px(50));...function UpdateStylesOften() { ... unitValueObj.value = 20; elementMaps[i].set("left-padding", unitValueObj); unitValueObj.value = 10; elementMaps[i].set("width", unitValueObj); ...}Doing this will not allow us to use the already existing internal representation of “width” value for “left-padding” since internally they have different representation. It is better to have a separate CSSTOM object for every different CSS property that will need frequent updating. Since there aren’t that many properties representable by CSSUnitValue this should be a negligible memory overhead.
// Preferlet widthObj = CSSStyleValue.parse("width", CSS.px(50));let leftPadObj = CSSStyleValue.parse("left-padding", CSS.px(50));...function UpdateStylesOften() { ... leftPadObj.value = 20; elementMaps[i].set("left-padding", leftPadObj); widthObj.value = 10; elementMaps[i].set("width", widthObj); ...}So overall for properties that will get updated often:
- Save
attributeStyleMaps to use set directly on the map instead of throughelement.attributeStyleMap - Reuse CSSTOM objects by changing their value with what you want to update, instead of creating new ones
- Be wary of using 1
CSSUnitValueobject for DIFFERENT CSS properties as they could have different internal representations which would slightly reduce performance.
© 2026 Coherent Labs. All rights reserved.