Course: JavaScript

Progress (0%)

CSSOM style Property

Chapter 53 20 mins

Learning outcomes:

  1. What is the style property
  2. Problem with the manual approach
  3. Working with style
  4. Limitations of style

Introduction

As we know, CSS on an HTML document can go essentially in three places, in an external .css file linked in the document via a <link> tag, in the <style> element, or inside the style attribute of an element.

What interests us right now is when the CSS goes in the style attribute of elements. The CSSOM standard extends the HTMLElement interface with a property to easily work with the inline styles of an element, i.e. the ones in its style attribute.

That property is style. An intuitive name, isn't it?

In this chapter, we'll explore this style property in detail; see how it's an instance of the CSSStyleDeclaration interface and allows us to get as well as set the inline styles of an element in a very intuitive manner.

We'll explore the exotic nature of CSSStyleDeclaration and some of its useful properties and methods. Not only this, but we'll also compare the style property with directly working with the setAttribute() and getAttribute() methods of an element.

Lastly, we'll have a little discussion on what the style property is and isn't meant for.

What is style?

Starting with the necessary details,

style is a property of the HTMLElement interface that allows us to work with the style HTML attribute of a given HTML element.

The style property returns back an instance of the CSSStyleDeclaration interface to help us in working with the HTML style attribute of an element.

As with almost all properties in the DOM (and CSSOM), style is an accessor property.

To learn more about accessor properties, refer to JavaScript Objects — Property Attributes.

We've already seen CSSStyleDeclaration in action in the previous chapter, but it was, more or less, read-only. The CSSStyleDeclaration instance returned by the style property can be read from and written to.

Recall that the interface allows us to easily and intuitively work with the styles as contained in a CSS style declaration block. For example, we can easily add a new style or remove an existing style from a given declaration block, with the help of CSSStyleDeclaration.

Talking about style, we can use it to specifically work with the style attribute of a given element, that is much like a style declaration block associated with the element in a stylesheet.

Technically, it's entirely possible to just rely on getAttribute() and setAttribute() to get or add/remove styles from an HTML element. However, as one could imagine, such an approach would be fraught with inefficiency and complexity.

Let's see some examples of working with the style property of an element via getAttribute() and setAttribute() and then witness the problem in using them to add/get/remove styles from an element.

Problem with the manual approach

Consider the following HTML code:

<p>A paragraph</p>

We are interested in setting the color of the <p> element to blue. So, likewise, let's head over to write some JavaScript to accomplish this.

First, we obviously select the element and then call setAttribute() on it to set to style attribute to the value 'color: blue'.

var paragraphElement = document.querySelector('p');

paragraphElement.setAttribute('style', 'color: blue');

When we load up the HTML page, the color of the element indeed turns out to be blue.

A paragraph

So far, so good.

Now, let's suppose that we want to further add two styles to the element from this point onwards (not from the initial starting point): opacity: 0.6 and margin: 30px.

Surely, doing so isn't impossible, but just a little bit complex.

First we have to retrieve the existing value of the style attribute and then concatenate it with a string defining both of these style declarations. After this, we ought to set the style attribute to this string.

An illustration follows:

var paragraphElement = document.querySelector('p');

paragraphElement.setAttribute('style', 'color: blue');

// Add two new styles from this point onwards.
var style = paragraphElement.getAttribute('style');
paragraphElement.setAttribute('style', style + ';opacity: 0.6;margin: 30px');

As we run this code, expectedly, the desired styles get applied to the element.

A paragraph

But let's not forget the amount of effort that we need to put in in order to accomplish this fairly simple task.

To take this to the next level, suppose that from this point onwards, we need to set the styles opacity: 0.4 and color: orange and also remove the previous margin style.

Now what?

Well, let's continue on with our old approach, i.e. first get the value of the style attribute, then concatenate it with the string containing the new styles, and then finally set the attribute to the resulting string.

The code below demonstrates this:

var paragraphElement = document.querySelector('p');

paragraphElement.setAttribute('style', 'color: blue');

// Add two new styles from this point onwards.
var style = paragraphElement.getAttribute('style');
paragraphElement.setAttribute('style', style + ';opacity: 0.6;margin: 30px');

// Add two new styles from this point onwards.
style = paragraphElement.getAttribute('style');
paragraphElement.setAttribute('style', style + ';opacity: 0.4;color: orange');

A paragraph

But wait!

We didn't remove the margin style. One might think of adding the style margin: 0 in order to remove the margin style but, as you can reason, this doesn't remove the existing margin style from the element; instead, it adds a new one. And that's clearly not what we want.

For instance, suppose that before the application of the previous margin style the margin of the element was defined somewhere in an external stylesheet as margin: 60px. How can defining a new margin style reset it back to this style (of the stylesheet).

Still motivated to keep using getAttribute() and setAttribute(), we come up with the following solution.

Get the existing value of the style attribute, split it at the ; character to get an array of all the individual styles, and then search for margin in there. Once it's found, delete it from the array, and then join the remaining elements of the array using the same ; delimiter to obtain a string. Finally, set the style attribute to this string.

The code below accomplishes this idea:

var paragraphElement = document.querySelector('p');

paragraphElement.setAttribute('style', 'color: blue');

// Add two new styles from this point onwards.
var style = paragraphElement.getAttribute('style');
paragraphElement.setAttribute('style', style + ';opacity: 0.6;margin: 30px');

// Add two new styles from this point onwards.
style = paragraphElement.getAttribute('style');
paragraphElement.setAttribute('style', style + ';opacity: 0.4;color: orange');

// Remove the margin style.
style = paragraphElement.getAttribute('style');
var styles = style.split(';');
var newStyles = [];
for (var i = 0; i < styles.length; i++) {
   if (styles[i].indexOf('margin') === -1) {
      newStyles.push(styles[i]);
   }
}
paragraphElement.setAttribute('style', newStyles.join(';'));

Let's run it and see the output:

A paragraph

It does work! The styles indeed get applied and our margin style has been reset back to its previous value.

But clearly, this time the code isn't a charm to look at.

Now, let's suppose that we want to add three new styles transform: translate(20px), background-color: yellow and width: 300px and remove the previous styles...

You get the idea, right?

Working with inline styles of an element via the getAttribute() and setAttribute() methods is possible but extremely inefficient and inconsistent.

At one point, we'd be using one way to accomplish something; at another one, we'd be using another way to accomplish that same thing. There's just no sensible and consistent interface between the code and the HTML style attribute of the element if we go with this manual way of working with it.

Fortunately, a much more simpler and efficient way is to use the style property of the element to work with its style attribute, and that in an object-oriented approach.

Let's explore the style property inside-out.

Working with style

There are essentially two ways of getting, setting and/or removing styles from a given element using the CSSStyleDeclaration instance returned by the style property of that element.

  1. Use methods of the CSSStyleDeclaration interface.
  2. Use the exotic nature of CSSStyleDeclaration.

Starting with the former case, CSSStyleDeclaration defines the following methods to get, set and/or remove styles:

  • getPropertyValue(propName) — gets the value of a given style property.
  • setProperty(propName, propValue) — sets a given style property on the element.
  • removeProperty(propName) — removes a given style property from the element.

Now, for the latter case, CSSStyleDeclaration exhibits exotic behavior in that when we set a property (a normal JavaScript object property) on it or retrieve a property, the interface taps into these operations and internally calls the same methods discussed above to handle these operations.

For example, setting the property color to the string 'blue' internally calls setProperty('color', 'blue'). And similarly retrieving color internally resolves down to a call to getPropertyValue('color').

Note that akin to the DOMStringMap interface that's used by the dataset property, there are no properties, like color or opacity, actually defined on the CSSStyleDeclaration instance returned — it purely notes the name of the property referred to and then calls either of the methods listed above depending on the context in which we used the property.

And in this regard, there is another similarity between CSSStyleDeclaration and DOMStringMap. That is, when a property is set in camel-case, it's thereafter converted by the interface to a corresponding hyphenated string.

For example, if we set the property backgroundColor to 'blue', internally a call is made to setProperty('background-color', 'blue'). Notice the first argument passed into the method and how it differs from the property originally set.

Alright, it's now time for a couple of examples.

Well, let's stick to the examples from the previous section in order to truly appreciate the importance of the style property.

Reconsider the following HTML:

<p>A paragraph</p>

In the code below, we set the color of the element to blue:

var paragraphElement = document.querySelector('p');

paragraphElement.style.color = 'blue';

Let's now see the output:

A paragraph

As expected, it works. Amazing!

In the following code, from this point onwards, we set the styles opacity: 0.6 and margin: 30px:

var paragraphElement = document.querySelector('p');

paragraphElement.style.color = 'blue';

// Add two styles from this point onwards.
paragraphElement.style.opacity = '0.6';
paragraphElement.style.margin = '30px';

A paragraph

See how much simpler the code is compared to the previous approach using getAttribute() and setAttribute(). We don't have to worry about any previous styles; setting a property on style effectively sets the inline style, be that a new one or the replacement of an old one.

For the third example, suppose we now have to add the styles opacity: 0.4 and color: orange, and remove the margin: 30px style.

Well, it's all very simple as shown in the code below:

var paragraphElement = document.querySelector('p');

paragraphElement.style.color = 'blue';

// Add two styles from this point onwards.
paragraphElement.style.opacity = '0.6';
paragraphElement.style.margin = '30px';

// Add two more styles from this point onwards.
paragraphElement.style.opacity = '0.4';
paragraphElement.style.color = 'orange';

// Remove the margin style.
paragraphElement.style.margin = null;

A paragraph

Woah! The code is really intuitive to read through. Just by setting the margin property to null, we effectively get the style property to be removed.

Purely splendid.

The cssText property

Often times, the addition or removal of an element is done on a per-style basis.

For instance, if we wish to set opacity: 0.6 and margin: 30px on a given <p> element, we'd do the following:

var paragraphElement = document.querySelector('p');

paragraphElement.style.opacity = '0.6';
paragraphElement.style.margin = '30px';

However, this isn't always going to be case. Sometimes, we might have a string of all the styles with us beforehand. And in this case, we're better off at dumping all the styles into the style attribute at once.

Obviously, one option in this case is to use setAttribute() to set the style attribute to the given string of styles. But recall that the CSSStyleDeclaration interface also provides a property cssText to do exactly the same thing.

Below shown is an example of its usage:

var paragraphElement = document.querySelector('p');

var styleStr = 'opacity: 0.6;margin: 30px';
paragraphElement.style.cssText = styleStr;

A paragraph

Limitations of style

As we've seen thus far, the style property of an element node is an extremely simple thing to understand. There really isn't any complexity involved in it.

However, while we do use style, there are a couple of things to keep in mind.

style only applies to inline styles

Firstly, style doesn't magically give us access to all the styles of a given element. Instead, it only gives access to the inline styles of a given element, i.e. what goes or is already there in the style attribute of the element.

As an example, consider the following HTML code:

<style>h1 {color: blue}</style>
<h1>A heading</h1>

Let's go ahead, select the <h1> element, and then retrieve its color:

var h1Element = document.querySelector('h1')
undefined
h1Element.style.color
''

See? We get '' returned upon inspecting style.color, yet we can clearly see that there is indeed a color: blue style set on the <h1> element.

As stated before, there isn't anything erroneous in this — h1Element.style.color is only meant to return the value of the color CSS property as applied to the <h1> element via its style attribute. That's it!

The style property does NOT provide any kind of access to all the styles applied to a given element; it's only concerned with the inline styles of the element.

style doesn't compute property values

Secondly, style also doesn't magically resolve property values.

For example, if we set style.width = '50%' and then later on retrieve style.width, we should expect the exact same '50%' value to be returned back; not any computed value, such as '100px' (given the parent of the element is 200px wide).

Simply put, style.prop returns back the exact value of the CSS property prop as set inside the style attribute, if at all. If there is no such property defined, '' is returned back.

To obtain a collection of computed CSS property values, we use the getComputedStyle() function on the element node. We'll see more to this function later on in the upcoming JavaScript CSSOM — Computed Styles chapter.

"I created Codeguage to save you from falling into the same learning conundrums that I fell into."

— Bilal Adnan, Founder of Codeguage