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.
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.
- Use methods of the
CSSStyleDeclaration
interface. - 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')
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.
getComputedStyle()
function on the element node. We'll see more to this function later on in the upcoming JavaScript CSSOM — Computed Styles chapter.