Changing inline styles with JavaScript
This is part of a series of articles about modern approaches to manipulating CSS with JavaScript:
- Part one: Inline styles (this article)
- Part two: Custom Properties
- Part three: Stylesheets (coming soon!)
There are multiple approaches to manipulating inline styles with JavaScript. One has been around for over a decade. Another is the Typed OM. The initial spec for Typed OM was released in 2016. Chrome shipped in 2018. Safari shipped in version 16.4. Firefox has a positive view of the proposal but has not implemented Typed OM yet. In this article I’m going to compare the different approaches.
The following examples assume we have the following element in our HTML:
<p style="width: 200px;">Lorem ipsum</p>
And we’ve selected the element with JavaScript:
const p = document.querySelector('p');
Remove an inline style
p.style.width = "";
With the Typed OM:
p.attributeStyleMap.delete('width');
Remove all inline styles
p.style = "";
With the Typed OM:
p.attributeStyleMap.clear();
Add or override an inline style
p.style.width = "50%";
This is a simple syntax to remember. CSS values that contain a dash need to use camelCase. So if we were setting the CSS min-width
property we would write minWidth
:
p.style.minWidth = "50%";
Alternatively we can use style.setProperty()
. Because we specify the property as a string, we write min-width
rather than minWidth
p.style.setProperty('min-width', '50%');
With the Typed OM:
p.attributeStyleMap.set('min-width', CSS.percent(50));
The Typed OM introduces a large amount of new syntax. In the above example I’m setting a percent value but there’s an equivalent syntax for just about any CSS unit: CSS.px()
, CSS.em()
, CSS.rem()
, CSS.vw()
etc. There’s also CSS.number()
for setting things like z-index
. If you need a keyword value like auto
or block
, there’s new CSSKeywordValue
:
p.attributeStyleMap.set('display', new CSSKeywordValue('none'));
While it’s probably not the recommended approach, setting the value with a string does also work:
p.attributeStyleMap.set('width', '50%');
Add an !important
inline style
What if you need the inline style to override a style that’s using !important
?
With attributeStyleMap.set
there isn’t a way to make the style !important
. Equally the following code would not work: p.style.minWidth = "50% !important";
The only option for an !important
inline style is setProperty()
. You specify the style as important with an optional third argument. Note that unlike in CSS, you don’t include the exclamation mark at the front:
p.style.setProperty('min-width', '50%', 'important');
Get inline styles
p.style.width;
This will return the width as a string (e.g. '200px'
). If an inline style has not been set for the particular property, an empty string will be returned.
With the Typed OM:
p.attributeStyleMap.get('width');
If an inline style has not been set for the particular property, null will be returned.
If you need to do maths using the value, Typed OM is a better option. Rather than returning a string it will return the value as a number and the unit separately {value: 200, unit: 'px'}
.
attributeStyleMap
will return the value using whatever unit was used to define it in CSS. So if your inline style was style="width: 50vmin;"
the result would be CSSUnitValue {value: 50, unit: 'vmin'}
. If you used the keyword value auto
, you’d get back CSSKeywordValue {value: 'auto'}
.
Conclusion
Articles and tweets from various Google employees claim the Typed OM API is faster than the older method.
Eric Bidelman writes: “The browser has to do less work serializing and deserializing string values. Now, the engine uses a similar understanding of CSS values across JS and C++.“
Here’s Alex Russell of Microsoft Edge:
The cool thing about the Typed OM is that we avoid the JS object -> string -> parse loop. That actually often involves a UCS2 -> UTF8/16 conversion when you do:https://t.co/BBmMlig2kG.width = "10px";
— Alex Russell (@slightlylate) April 21, 2022
This is MUCH cheaper:
n.attributeStyleMap.set("width", CSS.px(10));
I can’t say I’ve ever noticed performance issues when applying a style with JavaScript the old fashioned way, but if you’re continuously updating a style with requestAnimationFrame
, for instance, it might make a noticeable difference.