Why are styles invisible, and style tags not re-appendable after using insertRule of CSSOM
Asked Answered
C

1

8

If I've added styles with CSSOM using insertRule I've noticed two things.

The added styles don't appear in the html while viewing in Firebug ever.

The added styles don't work if the style tag is appended (ex: moved from head to body) to another element (Happens in Firefox, and Chrome).

If the styles are added after the tag is appended then they do work. They still don't show in Firebug. When appending the sheet has to be reassigned (regetted?) which makes it appear even stranger.

For not showing in Firebug it could be a quirk with Firebug, but regular styles that are not added dynamically show up.

For the styles not working after the append I'm wondering if this is the standard because this happens in Firefox, and Chrome. Looking at the standards I didn't see anything about this. Unless I just don't understand them.

var style = document.createElement('style'),
    sheet = style.sheet;
document.head.appendChild(style);
//When line 6 is un-commented the styles work
//if line 8 is also commented out.
//document.querySelector('.container').appendChild(style);
//Get the sheet when line 6 is un-commented
sheet = style.sheet
sheet.insertRule('.test{color: red}');
document.querySelector('.container').appendChild(style);
//styles don't apply after the previous line

Edit for clarity:

If you append a <style></style> tag to the <head></head> of html you can apply styles with style.sheet.insertRule(styleString), and added styles will apply for the document.

If you have already appended that <style></style> to the <head></head> like <head><style></style></head>, and attempt to append <style></style> somewhere else like <div><style></style></div> all the styles are lost, and do not apply again.

Is this normal?

The code flow:

Works:

  1. append <style> any where
  2. add styles with style.sheet.insertRule(styleString)

Doesn't work:

  1. append <style> any where
  2. add styles with style.sheet.insertRule(styleString) to <style>
  3. append same <style> somewhere else

My other issue is that styles added to <style></style> don't show up in Firebug even if they have applied to the document.

Edit more clarity:

If I reappend the style element without having modified the stylesheet, the styles remain:

var style = document.querySelector('style');
document.head.appendChild(style);
* {color: red}
<p>Hello world</p>

But if I have altered the stylesheet with JS, the changes are undone:

var style = document.querySelector('style'),
    sheet = style.sheet;
sheet.insertRule('* {color: red}', 0);
document.head.appendChild(style); //Comment this line out, and this works.
/* CSS rules will be inserted with JS */
<p>Hello world</p>
Copepod answered 15/4, 2016 at 4:5 Comment(16)
Not certain what Question is?Stroy
Mainly is the fact that styles don't apply after appending a style tag that already has styles added with insertRule normal?Copepod
If interpret Question correctly this would be similar to div{color:green};div{color:blue} blue would be color set at div as it is last declaration. See #1043501Stroy
That doesn't appear to be the problem. If I add the embedded <style> by hand to the html then move it with appendChild then the hand written styles in that tag apply.Copepod
"If I add the embedded <style> by hand to the html then move it with appendChild then the hand written styles in that tag apply" Yes. The specificity of the style attribute at html element should take precedence. Did you read all of the answers at linked Question? See also https://mcmap.net/q/81290/-how-are-the-points-in-css-specificity-calculated , w3.org/TR/CSS2/cascade.html#specificityStroy
Specificity doesn't make sense because the manual, and javascript style creation methods are done in different tests. The <style> tag is still being placed in the same location, but only works with manual (hand written) placement. In either test there is only one <style> tag, and no styles below it.Copepod
Still not gathering what actual Question is; or what expected result is? Can you create two stacksnippets demonstrating "Works" and "Doesn't work" at Question?Stroy
Be aware the insertRule requires 2 arguments. And using querySelector('style') makes no sense if you don't have any <style> element (here it worked because stack snippets insert a stylesheet).Quetzal
Basically, it seems that when you append the style element, a new stylesheet is created from the text contents of the style, not from the old one. Not sure if this is standardised, you can try looking at CSS Object Model, Document Object Model and maybe HTML5 specs.Quetzal
@Quetzal I know. Actually it works anyway because it only fails if the index is below plus one of what the next input would add. Using insertRule once without the second argument still works even in a local webpage without stack snippits.Copepod
@Orial What? I have looked at the standards. What I'd like to know is how is the first thing working, but the second not. There's nothing in the standards about that. There is something about owner nodes, but how does that resolve the discrepancy between the two methods in the question.Copepod
I noticed the edit. I'm concerned that it doesn't emphasise that they worked in the first place on the first append, and also that they do work when appended to another node other than head with the hand written version.Copepod
@QuentinEngles What is the purpose of appending <style> already in <head> to <head>?Stroy
@QuentinEngles Of course, feel free to improve or roll back my edit. But be aware you are not supposed to include a full page in the HTML section, only a fragment which stack snippets will wrap inside <body>.Quetzal
@Quetzal The purpose is for having an api that auto-appends to the head, but in case the user wants to change they can opt to append somewhere else.Copepod
@Quetzal The changes are mostly fine. I'll adjust them if there's any ambiguity for any one that wants to answer. Thanks for helping with the formatting.Copepod
S
8

This is because <style> elements only have a sheet property when they are appended to the doc.
Hence, when you do move it, or remove it from the document, their sheet property is set back to null. Every rules you applied to it using the insertRule method will have disappeared since they're not inside the <style>'s innerHTML.


Relevant part of the specs :

The update a style block algorithm for CSS (text/css) is as follows:

  1. Let element be the style element.

  2. If element has an associated CSS style sheet, remove the CSS style sheet in question.

  3. If element is not in a Document, then abort these steps.

  4. If the Should element's inline behavior be blocked by Content Security Policy [...] then abort these steps. [CSP]

  5. Create a CSS style sheet with the following properties: ...

As you can see, each time the <style> element is updated, a new CSS style sheet is created, (only if .3 and .4 are not blocking the process).


Small demo :

var style = document.createElement('style');
console.log('before being appended : '+ style.sheet)
document.body.appendChild(style); 
console.log('after being appended : '+ style.sheet)
document.body.removeChild(style);
console.log('after being removed : '+ style.sheet)
Swastika answered 20/4, 2016 at 4:45 Comment(4)
Thanks. I still don't understand what makes this work differently for styles that have hand written text content from styles that are added by insertRule. Or maybe I should be asking why? There doesn't appear to be any purpose to discarding the sheet for one method, and not the other.Copepod
because insertRule is a method of the CSSStyleSheet object, and is not directly linked with the <style> element. When you remove the style element, the CSSStyleSheet is removed, and you've got a new, fresh one when you insert the <style> back. But since insertRule only acted on the CSSStyleSheet and not on the <style> itself, you loose every rules inserted. You can use the innerHTML property if you want to keep these.Swastika
That still doesn't make sense. Oh well. I'm sure there's a reason for it, but I don't get it. I can see how it works. I still don't see why.Copepod
so how can I get the styles from those tags?Germinate

© 2022 - 2024 — McMap. All rights reserved.