acenturyandabit
acenturyandabit

Reputation: 1418

Get <style> tag css to only operate on siblings and children?

I've recently come to prefer resuable UI modules in the form of single .js files, which manipulate the dom using div.innerText and so forth. I'm developing a UI framework of sorts (a new and better one I swear) and I plan on allowing other devs to write their own modules to extend my framework.

To ensure that two devs' work doesn't interfere with each other, I'm making my modules self-contained. Then,because they are self-contained, I can rapidly and even recursively deploy them in any div on a page; e.g. call uiElement.deploy(element) sets up the reusable uiElement with the element as a parent, through code like the following:

uiElement.deploy=function(root){
 uiElement.div=document.createElement("div");
 uiElement.div.innerHTML=`
  <style>
   button{
    background:red;
   }
  </style>
  <button>Hey!</button>`;
 root.appendChild(uiElement.div);
}

It all works pretty well, but when it comes to styling, I'm a bit wary of declaring <style> elements in the innerHTML, because they might adversely impact the styling of my other reusable modules.

So, I'm wondering, why hasn't the HTML standard decided that if you put a <style> element in a container other than <head>, it only operates on the container's children (i.e. ithe style tag's siblings) and their decendants? It feels like a good idea to promote code reusability.

And by the way, how might I avoid the problem I've stated above? My current thought is to give the div a unique ID and then edit the css in my <style> tag, by parsing the innerHTML with regex.

Upvotes: 3

Views: 654

Answers (3)

acenturyandabit
acenturyandabit

Reputation: 1418

I've revisited the problem and would have recommended to my past self: Shadow DOM!

Shadow DOM can give CSS elements scope. The disadvantage is that you cannot access elements from the document using document.getElementById, which sadly locks you out of a number of libraries e.g. svg.js.

Here's how to use a shadow root, if you have some DOM element:

let el=document.createElement("div");
el.attachShadow({mode:'open'})
let st=document.createElement("style");
st.innerHTML=`
div{
    background:blue;
}
`
el.appendChild(st);

Upvotes: 0

Mouser
Mouser

Reputation: 13304

CSS stands for Cascading Style Sheets. The cascading suggests that it is poured down over every element starting at the root node: document. The specification states that any style-element always applies to the whole document.

My solution to your question of applying a own style to the element. However this solution is not elegant and can be solved better, since it will clutter the document with style-elements whenever an element is added.

uiElement.deploy=function(element, className){
 uiElement.div=document.createElement("div");
 uiElement.div.innerHTML=`
  <style>
   button.${className}{
    background:red;
   }
  </style>
  <button class="${className}">Hey!</button>`;
 element.appendChild(uiElement.div);
}

Better would be to add a link-element which points to a css-file that has style information about your code.

uiElement.deploy=function(element, className){
 uiElement.div=document.createElement("div");
 //link element - if not present in document: add.
 if (!document.querySelector(`link[href='location/${element}.css']`))
 {
     const link = document.createElement("link");
     link.href = `location/${element}.css'`;
     document.head.appendChild(link);
 }
 uiElement.div.innerHTML=`
  <button class="${className}">Hey!</button>`;
 element.appendChild(uiElement.div);
}

A stylesheet file (.css) also provides easier and more flexible management of your code, not needing to change the js-file if you just want to change the visual appearance.

Even in the situation above I would highly suggest to set a unique ID or class name to your created elements to differ in your CSS-rules, because CSS-rules are valid for the whole document.

Upvotes: 1

MikeB
MikeB

Reputation: 623

Give your outer element an ID if it doesn't already have one, (or possibly a class), then you can write your CSS snippet to only apply to the children of that element: #thisID button { ... }

Upvotes: 1

Related Questions