Dynamic CSS with CSS Object Model in JavaScript

The CSS Object Model (CSSOM) is an application programming interface (API) that represents CSS styles as a structured tree of JavaScript objects. This article explains how the CSSOM enables developers to dynamically inspect, insert, modify, and delete stylesheets and individual style rules at runtime using JavaScript, providing a more performant and programmatic alternative to standard inline styling.

Understanding the CSSOM Interface

When a browser loads a webpage, it parses the HTML into the Document Object Model (DOM) and the CSS into the CSS Object Model (CSSOM). While the DOM represents the page structure, the CSSOM represents the associated styling rules. JavaScript can access the CSSOM globally via the document.styleSheets collection, which returns an array-like StyleSheetList containing all <link> and <style> elements attached to the document.

Reading Styles and Rules

To read existing style rules, you traverse the document.styleSheets collection and access individual rule lists:

// Access the first stylesheet in the document
const sheet = document.styleSheets[0];

// Access the list of CSS rules inside the stylesheet
const rules = sheet.cssRules || sheet.rules;

// Read the selector and styling of the first rule
console.log(rules[0].selectorText); // e.g., "body"
console.log(rules[0].style.backgroundColor);

For elements whose styles are calculated through the cascade, inheritance, or external stylesheets, the window.getComputedStyle(element) method reads the final, computed properties applied by the browser.

Writing and Modifying Stylesheets

The CSSOM provides explicit methods to alter rules without directly manipulating the HTML DOM:

  1. Inserting Rules: The insertRule() method adds a new CSS rule to a stylesheet at a specified index.

    sheet.insertRule('.dynamic-class { color: red; font-size: 16px; }', sheet.cssRules.length);
  2. Deleting Rules: The deleteRule() method removes a rule at a given index.

    sheet.deleteRule(0); // Removes the first rule
  3. Modifying Existing Properties: You can update properties within existing rules using the style object or the setProperty() method:

    rules[0].style.setProperty('background-color', '#f0f0f0');

Constructable Stylesheets

Modern browsers also support Constructable Stylesheets via the CSSStyleSheet constructor, allowing developers to create and share styles across multiple components (such as Shadow DOM trees) efficiently:

// Create a new stylesheet
const dynamicSheet = new CSSStyleSheet();

// Apply CSS text synchronously
dynamicSheet.replaceSync('p { line-height: 1.5; color: #333; }');

// Adopt the stylesheet to the document or a shadow root
document.adoptedStyleSheets = [...document.adoptedStyleSheets, dynamicSheet];

Advantages of CSSOM Manipulation

Manipulating styles via the CSSOM rather than altering inline styles on individual DOM nodes improves rendering performance and maintainability. When you modify a single CSSOM rule, the browser applies that change across every matching element simultaneously, avoiding repetitive DOM updates and reducing layout thrashing.