Course: JavaScript

Progress (0%)

  1. Foundation

  2. Numbers

  3. Strings

  4. Conditions

  5. Loops

  6. Arrays

  7. Functions

  8. Objects

  9. Exceptions

  10. HTML DOM

  11. CSSOM

  12. Events

  13. Drag and Drop

  14. opt Touch Events

  15. Misc

  16. Project: Analog Clock

CSSOM Introduction

Chapter 51 16 mins

Learning outcomes:

  1. What is the CSSOM
  2. Important CSSOM interfaces
  3. Working with stylesheets
  4. Working with style rules
  5. What we'll cover in this unit

Back in time

Fast backwards in time, when JavaScript was first made public in the browser Netscape Navigator 2.0, in 1995, with a very trivial DOM API providing access to only a few set of elements, CSS was still a thing to be formally specified.

It was in 1996 that the world got the first ever specification of CSS. But during this time, as the idea of DHTML began to gain traction and it became possible to modify the style of HTML elements via styling attributes such as color, bg-color and border, the DOM API was extended to allow for the modification of these attributes in order to programmatically change the styles of HTML elements.

Later, as CSS was slowly introduced into the engines of browser vendors, some CSS specific interfaces were also created in addition to yet more extensions to the DOM API to allow for programmatic access of CSS styles.

The DOM Level 2 specification included two separate documents to formally define stylesheets and CSS-specific interfaces in the DOM API. These specifications were, thereafter, gradually adopted by implementors, but soon they were to be replaced with more rigorous set of specifications.

For a pretty long time, web developers continued using these CSS-specific APIs and the DOM API to work with the styles of HTML documents.

However, as CSS was on the verge of expansion with work already begun on CSS 2.0, anticipated to introduced many new features into the language, it was apparent that the current ideology of addressing CSS-specific features via the DOM specification wasn't going to suffice for long. With the continuously rising complexity of CSS, specification writers and implementors of CSS-specific interfaces in the DOM API felt the need for a rewrite.

Many CSS-specific interfaces were poorly named, some were poorly designed from the ground up with extremely inconsistent behavior across implementations. It was crucial to deprecate such interfaces in favor of a better and more concrete design of the entire CSS-specific API.

This whole scenario built the necessary tention and motivation to come up with a more powerful, more flexible, and much simpler model to address teh idea of programmatically working with CSS in the browser.

The outcome of this motivation was the CSSOM specification, published in 2011 by the W3C.

Let's see what exactly is the CSSOM...

What is CSSOM?

If the understand the DOM, then making intuition of the CSSOM won't be any difficult for you.

To start with, can you guess the full-form of the word CSSOM?

In simple words:

The CSS Object Model, or CSSOM for short, is a set of APIs meant to programmatically work with the styles of HTML/XML documents.

The CSSOM is literally a 'model' of the CSS associated with a given document, just like the DOM is a model of a document. The nomenclature of both these terms is pretty amazing.

As MDN describes the CSSOM:

It [the CSSOM] is much like the DOM, but for the CSS rather than the HTML.

As stated before, the sole purpose behind the CSSOM is to separate styling concerns from the DOM. So, as it works today:

  • The WHATWG DOM standard defines core DOM functionality.
  • The WHATWG HTML standard further extends the core DOM with HTML-specific features.
  • The W3C CSSOM standard defines interfaces to work with the styles of elements in HTML/XML documents.

Nice, isn't this?

The CSSOM is more than just a specification to simplify the work of specification writers and implementors. Akin to the DOM, the browser builds a CSSOM tree in order to used later on in the rendering stage of the underlying document, be that an HTML or an XML document.

Talking specifically about an HTML document, here's how it goes:

Once the browser is done loading and consequently parsing an HTML file, it creates a DOM tree out of it in order to make sense of the structure and the content of the document.

After this, it gathers all the external and internal stylesheets in the document, as well as all inline styles applied to elements, and then constructs a CSSOM tree using them. This is kind-of similar in nature to the DOM tree, but obviously not the same thing.

Thereafter, both of these trees are melded together to produce something called the render tree. This render tree is what the browser ultimately uses to paint the pixels of the document on the screen.

Modifications of the styles of an HTML document happen to its corresponding CSSOM tree, akin to how modifications to the structure and the content of the document happen to the DOM tree.

It's worth mentioning here that the CSSOM is separate from the DOM, yet some features found in some DOM interfaces are part of the CSSOM specification.

This is either due to legacy purposes of having to support the old interfaces, or because those features of the DOM interfaces aren't used in the construction of the CSSOM tree, and are merely provided to access certain stylistic characteristics of given elements.

Imporant CSSOM interfaces

Now that we know what exactly the CSSOM is, we can turn our attention to consider some of its most important interfaces at our dispense.

Starting with the most obvious thing, a stylesheet (internal or external) in an HTML/XML document is represented by the base abstract class StyleSheet. StyleSheet is inherited by CSSStyleSheet, an interface meant to only model CSS stylesheets.

Recall that a CSS stylesheet is comprised of various rules, i.e. style rules (the ones with a set of selectors and style block)import rules, keyframe rules, and so on. Following this idea, CSSStyleSheet defines a property called cssRules that returns back a CSSRuleList instance.

As the name suggests, CSSRuleList is a list of CSS rules. Each item of this list is an instance of a subclass of CSSRule, which generically represents any kind of a rule in a CSS stylesheet. Some subclasses of CSSRule are CSSStyleRule, CSSImportRule, CSSKeyframesRule, and so on.

Focusing on CSSStyleRule, it represents a style ruleset, which is comprised of a set of selectors followed by a style declaration block.

For example, below shown is a CSS style rule, whose selector is body and whose style block consists of just one style declaration, which is that of background-color:

/* A style rule. */
body {
   background-color: blue;
}

The CSSStyleRule interfaces models this entire style rule. It defines a property selectorText to access the set of selectors, as a string, and another property style to access the style declaration block of the rule.

The style declaration block could further be divided into various pieces and so is it actually.

In particular, the CSSStyleDeclaration interface represents the declaration block and is, perhaps, the most important interface of the CSSOM API since it's used in most JavaScript programs by virtue of the style attribute of HTML elements.

Moving on, the styleSheets property of the Document interface for an HTML document returns back a StyleSheetList instance, which denotes an ordered list of stylesheets. StyleSheetList, like almost all list-like interfaces in JavaScript, provides index keys for easy enumeration of the contained items.

The styleSheets property is surely a quick way to obtain a collection of all the stylesheets in an HTML document and then select a given stylesheet from that collection, but it isn't the only way to obtain a given stylesheet.

We can also directly access a <link> element whose rel attribute is set to "stylesheet" or access a <style> element from the HTML document, using DOM methods, and then retrieve the value of its sheet property.

The sheet property of both the HTMLLinkElement (representing <link>) and the HTMLStyleElement (representing <style>) interfaces return the underlying CSS stylesheet of a given element, or null if the element doesn't have an underlying stylesheet (for e.g. a <link> element to represent the favicon of the document).

So, to sum it up, this is a glimpse of the huge set of interfaces put forward by the CSSOM API. In the following sections, we'll dig deeper into some of these interfaces.

Working with style sheets

In this section, we'll explore the StyleSheet and CSSStyleSheet interfaces to work with CSS style sheets in HTML documents.

Before we begin, note that it's not really necessary to understand every single detail or memorize every single property/method as follows. Although, at the time of this writing, all major browsers do support StyleSheet and CSSStyleSheet completely out of the box, working with these interfaces isn't common and even in most of the applications that you'll be building, you won't need to use them.

Likewise, take the following discussion as surplus knowledge that you can use some day. If you want to, you could skip this section, to the next one.

The StyleSheet interface is an abstract base interface to represent any kind of a stylesheet in an HTML/XML document.

Some of its properties are as follows:

PropertyPurpose
hrefA string representing the URL of the stylesheet, if it was obtained externally.
ownerNodeThe node that owns the stylesheet, or null if there is none. For HTML documents, this is typically an element node (<link> or <style>).
typeThe type of the stylesheet. Nowadays, this is always the string 'text/css'.
mediaA MediaList instance specifying the media at which the stylesheet applies.

StyleSheet defines no methods.

The CSSStyleSheet interface, derived from StyleSheet, purely represents CSS stylesheets.

It defines a handful of properties and methods, some of which are shown below:

Property/methodPurpose
cssRulesReturns a CSSRuleList instance containing all the rules in the stylesheet.
insertRule()Inserts a new rule into the stylesheet.
deleteRule()Removes a given rule from the stylesheet.

Let's take a look at a couple of examples.

Consider the following HTML code:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Working with the CSSOM</title>
   <link rel="stylesheet" href="style.css">
   <style>
      h1 {color: blue}
   </style>
</head>
<body>
   <h1>Working with the CSSOM</h1>
   <p>The CSSOM API is interesting to use.</p>
</body>
</html>

There are two stylesheets in here: one is an external stylesheet linked via the <link> element while the other is an internal stylesheet contained in the <style> element.

The style.css stylesheet is as follows:

style.css
body {
   margin: 40px;
}

Now we can obtain both of these stylesheets via the document.styleSheets collection (which is a StyleSheetList) instance.

In the following JavaScript code, we access both the stylesheets above and then log their href and the nodeName of their ownerNodes in a nicely formatted way:

var styleSheets = document.styleSheets;

for (var i = 0, len = styleSheets.length; i < len; i++) {
   console.log('Stylesheet', i + 1);
   console.log('Href:', styleSheets[i].href);
   console.log('Owner:', styleSheets[i].ownerNode.nodeName);
   console.log(''); // Empty line.
}

Live Example

Here's the console output generated:

Stylesheet 1 Href: https://www.codeguage.com/courses/js/examples/style.css Owner: LINK Stylesheet 2 Href: null Owner: STYLE

The first stylesheet is an external stylesheet associated with a <link> element, hence the shown href and ownerNode. The second stylesheet is an internal one associated with a <style> element, obviously without any URL, hence the shown href and ownerNode.

As stated before, document.styleSheets isn't the only way to access a particular set of stylesheets; we can even do this manually.

In the code below, we access both the <link> and <style> elements in the HTML markup above, and then get their sheet properties. This gives us references to both the underlying stylesheets, whose information we output in the same way we did above:

var styleSheet = document.querySelector('link').sheet;

console.log('Stylesheet 1');
console.log('Href:', styleSheets[i].href);
console.log('Owner:', styleSheets[i].ownerNode.nodeName);
console.log(''); // Empty line.

styleSheet = document.querySelector('style').sheet;

console.log('Stylesheet 2');
console.log('Href:', styleSheets[i].href);
console.log('Owner:', styleSheets[i].ownerNode.nodeName);

Live Example

Here's the console output:

Stylesheet 1 Href: https://www.codeguage.com/courses/js/examples/style.css Owner: LINK Stylesheet 2 Href: null Owner: STYLE

Perfect — it's exactly the same as before!

In this unit

Let's now discuss on what we'll be learning in the upcoming chapters of this CSSOM unit.

Starting with the next chapter, we'll explore the style property of the HTMLElement interface. It's used to set inline styles on given HTML elements and even retrieve the existing inline styles of those elements.

Often when we want to change the styles of given elements, it's the style property that we use. It's very simple to use, easy to understand, and quite compatible across browsers, even the old ones.

After this, we'll explore about the window's viewport. This is an extremely useful concept to wrap the mind around, since it allows us to execute code based on the width and height of the device — or more generally, the browser window — under consideration.

Moving further, we'll learn about bounding boxes, and how to retrieve the dimensions of given elements. In this regard, the HTMLElement interface is extended with the getBoundingClientRect() and getClientRects() methods that return DOMRect instances containing a sufficient amount of information regarding the geometry of the underlying element.

Next up, we'll see what are offsets and how to compute them for given elements, relative to various edges of the viewport, or to the left/top edge of the HTML page.

Offsets are yet another crucially important concept of the CSSOM API with a handful of properties and methods at our dispense to easily compute them.

Finally, we'll learn how to obtain the computed styles of elements with the help of the global getComputedStyle() function which returns a read-only live instance of the CSSStyleDeclaration interface.