4

It appears to me that all modern browsers including recent versions of Chrome, Safari and FireFox (possibly since the beginning) respect the order of style and link elements in the head; even when created dynamically and added during run-time using JavaScript.

For example, here red.css and green.css both specify the body background color; the first sets the body background red, the second sets it green:

<head>
    <!-- other code -->
    <link rel="stylesheet" href="red.css" type="text/css">
    <link rel="stylesheet" href="green.css" type="text/css">
</head>

The result is that background color of the body is green since green.css is placed after red.css and evaluated afterwards.

The ordering of elements appears to hold true even when the link elements are created dynamically and inserted into the head. For instance, dynamically creating a link element that loads green.css will only set the body background color green if it is inserted after red.css.

However, the only browser that does not seem to respect this is Internet Explorer (at least IE 7-9 do not). It appears that with IE the most recently added link or style element is evaluated on-top everything that has already been evaluated; it does not respect the tree order when added during run-time.

Is respecting the order non-standard behavior, or is this an Internet Explorer bug? How can I fix this for Internet Explorer?

An idea I have come up with (that works) is to dynamically remove all existing link and style elements and add them back in the same tree order -- which is the order I wish them to be evaluated.

Any insight would be greatly appreciated.

UPDATE

Here is a more detailed code sample as requested:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="red.css" type="text/css"> <!-- sets red -->
</head>
<body>

<script type="text/javascript">

    setTimeout(function() {

        // IE7-8 does not support referencing document.head
        var head = document.getElementsByTagName("head")[0];

        var link = document.createElement("link");
        link.setAttribute("href", "green.css");
        link.setAttribute("rel", "stylesheet");
        link.setAttribute("type", "text/css");

        // All modern browesers will leave the background
        // color red, except IE will set it green.
        head.insertBefore(link, head.firstChild);

        // Now comment out the above line and try adding the link
        // using this instead. All modern browsers (including IE)
        // will set the body background color green after two seconds.
        // IE seems to always evaluate the last dynamically added link.

        // head.appendChild(link);

    }, 2000);

</script>

</body>
</html>

Contents of red.css:

body { background-color: red; }

Contents of green.css:

body { background-color: green; }
Peter
  • 3,998
  • 24
  • 33
  • Are you saying that if the document only has the second link, then the first is added dynamically before the second, that in IE the first link takes precedence? I.e. that it doesn't "cascade" correctly? Can you provide a test case? – RobG Sep 03 '12 at 01:12
  • @RobG, yes exactly. In all my tests this has been the case with IE when dynamically creating `link` elements. Virtually all other browsers respect the placement order. – Peter Sep 03 '12 at 01:15
  • The issue seems to persist in IE9, your idea of dynamically adding all the style sheets in the required order is probably the best you can do. – RobG Sep 03 '12 at 02:03
  • Oh, it would be clearer if you called the style sheets in the example `red.css` and `green.css`. :-) – RobG Sep 03 '12 at 02:09
  • @RobG Thanks for trying IE9, I will update my question to include it. I suppose jostling IE may be the best solution. Oh, and that's a great idea too, I'll rename the sheets :) – Peter Sep 03 '12 at 02:09
  • "Is respecting the order non-standard behavior, or is this an Internet Explorer bug?" I don't know, but that's a very interesting question. I googled a lot and couldn't find any specs mentioning if the cascade should be re-evaluated by the user-agent in case a new stylesheet is added dynamically. – bfavaretto Sep 03 '12 at 14:10
  • @bfavaretto Cool, yea that's why I thought I'd ask it here. I wrote up a work-around based on o.v.'s suggestion. I'll post it shortly. – Peter Sep 04 '12 at 00:58
  • @Peter - Did the toggle attribute idea work? Like everyone else, I couldn't find any spec on evaluation order spanning stylesheet resources. [CSSOM](http://dev.w3.org/csswg/cssom/#document-style-sheets) has a concept of the `document style sheets` which are in the order HTTP Link: headers, then tree order, but nothing I could find says the resources must be evaluated in that order. – Alohci Sep 04 '12 at 10:13
  • @Alohci yes it did! However, it only seemed to work on the `link` elements, not the `style` ones -- that is changing the `type` attribute. Perhaps there is a different attribute that can be flipped. Anyhow, I have written up a nice little function that removes and adds all `link` and `style` elements in place, it seems to work. I'll post it shortly. Thanks. – Peter Sep 07 '12 at 06:18

3 Answers3

3

What if, instead of re-appending stylesheets, you were to toggle an attribute of theirs that would force re-rendering? For instance, you could try iterating over all link/style elements, set their media attribute to none and then re-set it back to the original.

Oleg
  • 24,465
  • 8
  • 61
  • 91
1

You don't tell us the details of what problem you're really trying to solve by inserting stylesheets, but it is likely that there are simply better ways to solve the real problem instead of dynamically inserting a style sheet in a specific order in the list.

For example, you could have both stylesheets (slightly modified to key off another class) in place and via adding or removing a single class to the <body> tag, you could trigger a change from green to red or vice/versa.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thanks for the insight, I do realize that some problems are problems that can be solved by avoiding them. However, this is not exactly the case here. This is for a non-intrusive JS library. The problem is actually easy to get around, we just want to minimize the number of ways users can shoot themselves in the foot. – Peter Sep 03 '12 at 07:23
0

What you're referring to is CASCADING - a very important function of the way CASCADING style sheets (CSS) work. All browsers work this way, including IE. If they didn't cascade, it would be a major problem.

However, there are some styles that don't work in some versions of IE - perhaps what you're looking at, is styles not working properly, as opposed to the cascading not working properly. Would you like to post a specific example?

zenkaty
  • 1,538
  • 9
  • 11
  • The cascade works on IE, but when new `link` or `style` elements are dynamically created and added during runtime, they are evaluated on-top of the existing cascade, regardless of where they are placed. The problem is that the tree order is not respected in IE when added dynamically. I would expect the entire cascade to be re-evaluated, like all other browsers do. Maybe this is not standard behavior? – Peter Sep 03 '12 at 01:18
  • I see. Is this what you're talking about? http://stackoverflow.com/questions/1184950/dynamically-loading-css-stylesheet-doesnt-work-on-ie – zenkaty Sep 03 '12 at 01:27
  • Thanks @zenkaty, I saw that too. That question does not deal with order of evaluation for the cascade like mine does. – Peter Sep 03 '12 at 01:29