Elkling trying out a little magic!

Playing with Houdini CSS, Part Two — Typed OM

Eoin Falconer
Norigin Media Tech Blog

--

Welcome Back

This is the second part of my series on Houdini CSS. This series is taking a hands on approach with the mildly theoretical topic and attempting to help people get up and running with Houdini. If you have not read Part One then I recommend clicking here first. These posts are designed to be easily and quickly consumed, in fact, skim-reading is encouraged!

What next?

As the title suggests, today we will be looking at another API within Houdini CSS, namely Typed OM. Luckily, Typed OM is well supported enough to get a decent hand-on look at what it can be used for!

Typed OM, for me, is the API which has the most impact on your everyday development, allowing you to use Houdini as a tool in your CSS toolbox. It aims to make working with both CSS and JavaScript together that little bit more cohesive. Dealing with CSSOM value strings can be difficult, messy and most of all incur a large performance overhead. Let’s have a deeper look at how Typed OM exposes CSS values as typed JavaScript Objects.

What’s currently our solution to CSSOM reading/setting?

As we know, CSS’ object model has allowed us to read CSS properties and edit them from JavaScript for a very long time. We’ve all done something like this:

let menu = document.getElementById('menu');
menu.style.backgroundColor = 'blue';
menu.style.backgroundColor // 'blue'

And honestly, this isn’t actually that bad. Your colour code is a string anyway, then this isn’t really an issue. The issue arises in a situation like this:

let menu = document.getElementById('menu');
menu.style.opacity = 0.23 // 0.23 is a number (great!)
typeof menu.style.opacity // string (really annoying)

In the example above, the opacity value returned to you by your CSSOM is in string format meaning that in order to work with it in a mathematical fashion you have to parse it to a number and then perform your operations on it. This seems counterintuitive and this is where Typed OM comes in to save the day.

How Typed OM… types the OM

Typed OM opens up a whole new way of assigning and reading values. Instead of using a string assign to a value in the object, your CSSOM is interfaced in a Map fashion. This Map object is accessed through the .attributeStyleMapproperty of the element at hand. This also means that you get all of the useful functions that normally come with a Map object giving us the following scenario:

let menu = document.getElementById('menu');
menu.attributeStyleMap.set('opacity', 0.23); // not much difference
typeof menu.attributeStyleMap.get('opacity'); // number, this is more like it// Also worth notingmenu.attributeStyleMap.has('opacity') // true|false
menu.attributeStyleMap.remove('opacity') // removes the style
menu.attributeStyleMap.clear // removes all styles
// And all the other Map like things you can do...

Above we can see that a number is returned when we try and read the opacity style of the element at hand. This means that we are left with more performant code and a neater solution.

The great thing about this is that you also get error handling. If you try and give opacity a string then you’ll get thrown an error, meaning that (finally) CSS is getting some type checks!

You can do conversions between absolute lengths and pixels, so if you’re looking to move something 1cm to the left, Typed OM will handle the pixel conversion for you!

window.getComputedStyle vs. el.computedStyleMap

Although I’m not exactly keen on naming two things that inherently have a returned value difference so similar, the actual concept of having both of these things available is really useful.

window.getComputedStyle() will return all the literal values in the map back to you with their former values, that have been set by your JavaScript or by your CSS.

el.computedStyleMap() will return clamped or rounded values back to you, meaning that things like out of bounds values and integer only properties are handled for you.

Numerical Values

CSS properties aren’t always as simple as a just giving in numbers for values. In fact, most of the time you are using things like degrees and pixels. Typed OM provides this for you and allows you to not only access the variable but also the type using the CSSUnitValue object.

const {value, unit} = CSS.number('10');
// value === 10, unit === 'number'
const {value, unit} = CSS.px(42);
// value === 42, unit === 'px'

const {value, unit} = CSS.vw('100');
// value === 100, unit === 'vw'

const {value, unit} = CSS.percent('10');
// value === 10, unit === 'percent'

const {value, unit} = CSS.deg(45);
// value === 45, unit === 'deg'

const {value, unit} = CSS.ms(300);
// value === 300, unit === 'ms'
// NOTE: All values can be passed as a String or a Number
// credit: https://developers.google.com/web/updates/2018/03/cssom
// You can view all the types at https://drafts.css-houdini.org/css-typed-om/#numeric-factory

Performing mathematical operations is also possible and intuitive:

// calc(2px + 10 * 6vw) is equiv. tonew CSSMathSum(
CSS.px(2),
new CSSMathSum(
new CSSMathProduct(10, CSS.vw(6))
)
);
// also available is add, sub, mul, div, min and max for all your arithmetic needs

Conclusion

In conclusion, Typed OM not only solves problems for developers and how they write their code, but it also impacts on the overall performance of your application. Tab Akins reports early performance benchmarks indicate that Typed OM is ~30% faster in operations/sec when compared to the traditional CSSOM string manipulations, making CSSOM manipulations noticeably more performant operations with things such asrequestAnimationFrame() for developing CSS animations.

--

--

Eoin Falconer
Norigin Media Tech Blog

Hi! My name is Eoin (Owen is the pronunciation you may be more familiar with). I am working as the CTO of Hospitality for Arribatec in Oslo, Norway.