Page-Level CSS Variables

Since IE & Edge don't currently support CSS variables, this is another approach. Particularly useful for things like white-labeling a SPA without having to build CSS files or tightly couple CSS to JS/HTML templates.

by nathanlogan

HTML

<div>
  <p>This is styled with dynamically-applied CSS?!</p>
</div>

<p>This too?!</p>

<p class="getDefault">But not this.  :( </p>

CSS

/* default CSS could be delivered to the page here... */
p {
  padding: 20px;
  background-color: orange;
}

JavaScript

////////////////////////////////////////////////////////////
// Variables to modify
////////////////////////////////////////////////////////////

// the CSS templates, with CSS variable syntax (this could also be created by parsing a CSS file)
let toStyle = [
  {
    selector: 'div',
    rules: 'padding: var(--standardPadding); background-color: var(--primaryBackgroundColor); border: 2px solid var(--secondaryBackgroundColor)'
  },
  {
    selector: 'p:not(.getDefault)',
    rules: 'padding: var(--standardPadding); background-color: var(--secondaryBackgroundColor); color: #fff;'
  }
]

// the variable names and values for replacement
const variables = {
  'primaryBackgroundColor': '#ccc',
  'secondaryBackgroundColor': 'navy',
  'standardPadding': '20px'
}

////////////////////////////////////////////////////////////
// Utility functions
////////////////////////////////////////////////////////////

// This function will create a new dynamic stylesheet.
// (from https://davidwalsh.name/add-rules-stylesheets)
const createNewSheet = function () {
  var style = document.createElement('style')

  // WebKit hack :(
  style.appendChild(document.createTextNode(''))

  // Add the <style> element to the page
  document.head.appendChild(style)

  return style.sheet
}

// This function is a cross-browser way to add style rules to a stylesheet.
// (from https://davidwalsh.name/add-rules-stylesheets)
function addCSSRule (sheet, selector, rules, index = 0) {
  // W3C-supported way...or IE way
  if ('insertRule' in sheet) {
    sheet.insertRule(selector + '{' + rules + '}', index)
  } else if ('addRule' in sheet) {
    sheet.addRule(selector, rules, index)
  }
}

////////////////////////////////////////////////////////////
// Logic to do the replacement and get it on the page
////////////////////////////////////////////////////////////

// create our dynamic stylesheet
let newSheet = createNewSheet()

// run through our elements to style
for (let i = 0, len = toStyle.length; i <...