DEV Community

Eckehard
Eckehard

Posted on • Edited on

Dynamically add CSS rules

CSS rules are used to format elements on a web page. They can be provided on different levels of your code:

  • External - by using a element to link to an external CSS file
  • Internal - by using a <style> element in the <head> section
  • Inline - by using the style attribute inside HTML elements

CSS stands for Cascading Style Sheets, the word "cascading" means, that a style applied to a parent element will also apply to all children elements within the parent [1]. The way, css rules are evaluated, may be rather complex. If two rules apply to the same element, the more "specific" rule is used (see here for more details).

If you define styles that apply to your whole page, CSS ist very efficient: Just changing the font style of your "body"-element inherits to all other elements on your page. The same is true if you change the visual appearance of element types like headlines, tables and so on.

But CSS is also used to style single elements, and here you have two options:
a) apply an inline style directly to the element
b) apply a class or an id to the element and add the class definition to the style sheet.

If you are working with dynamic page content, applying inline styles can be most useful:

let el = getElementById("myDiv")
el.style.color = "red"
Enter fullscreen mode Exit fullscreen mode

Here you do not need to define a class, which avoids external dependencies. You can write a function that works directly on the DOM to change the visual appearance of an element.

This works well, until you try to set a pseudo-class like ":hover"

Programmatical set pseudo classes

You will find that you cannot apply any "pseudo-classes" like :hover or :active as an inlin-style. So, what can you do make an elementy :hover programmatically?

Finally, the solution is pretty simple. Just, you cannot avoid the usage of Id´s or classes, but you can set any CSS definitions from within Javascript:

  <div id="myHover1">Text</div>
  <div class="myHover2">Text</div>
  <script>
    sheet = window.document.styleSheets[0]
    sheet.insertRule('#myHover1:hover { background-color: red; }', sheet.cssRules.length)
    sheet.insertRule('.myHover2:hover { background-color: green; }', sheet.cssRules.length)
  </script>
Enter fullscreen mode Exit fullscreen mode

You need to be carefull that properties for "hover" are not set as inline styles. An inline style is always the most specific, so the pseudo-class would not work. If you need a color-change, all properties have to be defined in the class like this:

    sheet.insertRule('#myHover1 { background-color: green; }', sheet.cssRules.length)
    sheet.insertRule('#myHover1:hover { background-color: red; }', sheet.cssRules.length)
Enter fullscreen mode Exit fullscreen mode

To make things a bit more "comfortable, I created this function that let´s you work with template literals as well:

/* ----------------------------------------------------------------------------
    CSS: create CSS-Defintions dynamically
    's' can be 
     - a string CSS(".myClass { color: red; }") 
     - a template with multiple rules
        CSS(`
          .myClass { color: red; }
          .myClass:hover { color: green }
        `)
   ----------------------------------------------------------------------------*/
function CSS(s) {
  let rule = "", rules = [], sheet = window.document.styleSheets[0]  // Get styleSheet
  s.split("}").forEach(s => {
    let r = (s + "}").replace(/\r?\n|\r/g, "");  // create full rule again
    rule = (rule === "") ? r : rule + r
    if (rule.split('{').length === rule.split('}').length) { // equal number of brackets?
      sheet.insertRule(rule, sheet.cssRules.length)
      rule = ""
    }
  })
}
Enter fullscreen mode Exit fullscreen mode

Comment: Creating CSS rules this way is not a common case. But there might be situations, where creating CSS definitons programmatically is helpful. In this case, the provided solution may serve you

Top comments (1)

Collapse
 
artydev profile image
artydev • Edited

Nice Eckehard, thank you :-)

You can give an eye here ustyler