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>
Oriol
  • 225,583
  • 46
  • 371
  • 457
Quentin Engles
  • 2,352
  • 1
  • 16
  • 31
  • 1
    Not certain what Question is? – guest271314 Apr 15 '16 at 04:37
  • Mainly is the fact that styles don't apply after appending a style tag that already has styles added with insertRule normal? – Quentin Engles Apr 15 '16 at 07:41
  • 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 http://stackoverflow.com/questions/1043001/what-is-the-meaning-of-cascading-in-css – guest271314 Apr 15 '16 at 14:31
  • That doesn't appear to be the problem. If I add the embedded ` – Quentin Engles Apr 15 '16 at 21:30
  • _"If I add the embedded – guest271314 Apr 16 '16 at 01:27
  • Specificity doesn't make sense because the manual, and javascript style creation methods are done in different tests. The – Quentin Engles Apr 16 '16 at 04:47
  • 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? – guest271314 Apr 16 '16 at 15:06
  • Be aware the `insertRule` requires 2 arguments. And using `querySelector('style')` makes no sense if you don't have any ` – Oriol Apr 16 '16 at 22:07
  • 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](https://www.w3.org/TR/cssom-1/), [Document Object Model](https://www.w3.org/TR/dom/) and maybe [HTML5](https://www.w3.org/TR/html5/) specs. – Oriol Apr 16 '16 at 22:17
  • @Oriol 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. – Quentin Engles Apr 16 '16 at 22:58
  • @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. – Quentin Engles Apr 16 '16 at 23:09
  • 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. – Quentin Engles Apr 16 '16 at 23:36
  • @QuentinEngles What is the purpose of appending ` – guest271314 Apr 17 '16 at 14:04
  • @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 ``. – Oriol Apr 17 '16 at 18:44
  • @Oriol 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. – Quentin Engles Apr 19 '16 at 08:05
  • @Oriol 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. – Quentin Engles Apr 19 '16 at 08:07

1 Answers1

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)
Kaiido
  • 87,051
  • 7
  • 143
  • 194
  • 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. – Quentin Engles Apr 20 '16 at 05:18
  • 1
    because `insertRule` is a method of the `CSSStyleSheet` object, and is not directly linked with the ` – Kaiido Apr 20 '16 at 05:24
  • 1
    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. – Quentin Engles Apr 20 '16 at 05:32