Dynamically add CSS rules
Tags: javascript, css, html, webdev
Published: 2023-05-14 22:58:05

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 <link> 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](https://www.w3schools.com/html/html_css.asp)\]. 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](https://www.w3schools.com/css/css_specificity.asp) 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:
```JS
let el = getElementById("myDiv")
el.style.color = "red"
```
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: 
```HTML
  <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>
```
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:
```JS
    sheet.insertRule('#myHover1 { background-color: green; }', sheet.cssRules.length)
    sheet.insertRule('#myHover1:hover { background-color: red; }', sheet.cssRules.length)
```
To make things a bit more "comfortable, I created this function that let´s you work with template literals as well:
```JS
/* ----------------------------------------------------------------------------
    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 = ""
    }
  })
}
```

***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