6

I have a site that requires two themes to be loaded. The second theme can be toggled on/off by the user. I'm currently accomplishing this by using the disabled tag in the link like so:

<link rel="stylesheet" href="{{main css}}">
<link rel="stylesheet" title="theme-white" href="{{2nd theme css}}" disabled>

I then toggle disabled in JavaScript.

This works great in Safari (Mac), Chrome (Mac/Windows), and IE10. However, Firefox (both Mac and Windows) seems to ignore the disabled tag on page load and displays the second theme on initial load (as it is loaded second). When I manually toggle disabled, however, Firefox does respond to the tag and will begin to switch the second theme on/off.

How can I accomplish this goal?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Gilman
  • 574
  • 1
  • 5
  • 12
  • What if you just switch the order of the stylesheets? That way all browsers, whether or not they initially recognize disabled, will still display the main CSS. – Hanna Aug 14 '13 at 16:48
  • can you tell us the rest of the codes? – Ali Çarıkçıoğlu Aug 14 '13 at 16:58
  • Unfortunately, I can't re-order the stylesheets because I need the themed styles to override the primary. I can't disable the initial stylesheet either (if I were to reorder them) because it's a combined/minified stylesheet with all vendor/site styles and I wouldn't want to duplicate that across both stylesheets. – Gilman Aug 14 '13 at 17:00
  • The only other part of the code that is relevant is how I switch the them on/off, which is : `stylesheet = $('link[title=theme-' + theme + ']')[0]` then based on user selection I set `stylesheet.disabled = true` or `stylesheet.disabled = false`. Firefox does respond to this manual switching of the disabled state but does not seem to respond when the page is initially loaded. – Gilman Aug 14 '13 at 17:02
  • If you're relying on Javascript anyway, can't you just insert and delete the entire link elements, instead of just the attribute? – Mr Lister Aug 14 '13 at 18:48
  • Yeah - I would be able to add the css to the dom after page load but then I'm separating out where my stylesheets are 'housed' and I think that makes for confusing code later on. I would not be able to 'remove' the stylesheet because I believe browsers cache the stylesheets - so the disabled option is necessary for toggling. I'm just confused why firefox doesn't honor the disabled tag on page load but _does_ after page has been loaded. – Gilman Aug 14 '13 at 19:24
  • "While there is no `disabled` attribute in the HTML standard, there **is** a `disabled` attribute on the `HTMLLinkElement` DOM object" (from [Mozilla's MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-disabled)). – Cristian Ciupitu Mar 06 '18 at 11:46
  • Looks like they are going to fix it (https://bugzilla.mozilla.org/show_bug.cgi?id=1281135) but won't be until v68 is released – Scott Ayers Jun 04 '19 at 19:13

4 Answers4

4

I found a workaround that seems to be functional in all browsers. This does NOT seem like it should be the best way to do it but I wanted to share.

This is not ideal for a few reasons but I tried to make it streamlined and without any external library dependency like jQuery because this needs to be placed in your head tag and you probably have not loaded your JS libraries at that point.

<script>
    window.onload = function() {
        var path  = "css";
        var style   = document.createElement( 'link' );
        style.rel   = 'stylesheet';
        style.href   = '/your/css/url.css';
        document.getElementsByTagName( 'head' )[0].appendChild( style );
        style.disabled = true;
    };
</script>

NOTE: Firefox seems to only respond to the disabled tag if it is applied to the stylesheet after it has been added to the DOM. I still feel like I'm missing something because that seems crazy.

So, if you were to put style.disabled = true; before you add the style to your document then Firefox does not recognize the disabled state of the stylesheet.

Hooman Bahreini
  • 14,480
  • 11
  • 70
  • 137
Gilman
  • 574
  • 1
  • 5
  • 12
  • This is along the same lines as I was thinking. However, instead of adding `style.disabled = 'true'`, I would only add the function to the `window.onload` event if we know that the user wants that theme enabled. Then call the function at later point if the user decides to enable that theme. – user1171848 Aug 15 '13 at 15:40
  • Good point. I was doing it this way so there would be no delay when switching themes -- I'll need to figure out how 'popular' the feature would be so I can optimize for either overall page load time or theme switching speed. – Gilman Aug 16 '13 at 16:05
  • see [this answer](https://stackoverflow.com/questions/19844545/replacing-css-file-on-the-fly-and-apply-the-new-style-to-the-page/19844757#19844757) for some great solutions for dynamically switching stylesheets. – Hooman Bahreini Nov 17 '18 at 07:11
3

This is fixed in Firefox 68. You can now set the disabled attribute on <link> elements that also contain the ref=stylesheet attribute value. This will prevent the browser from loading that stylesheet until the disabled attribute is set to false or removed via JavaScript or some other method.

This brings Firefox in line with Chrome, Edge, Safari on support for this feature.

More info on MDN: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#Attributes

Bugzilla report: https://bugzilla.mozilla.org/show_bug.cgi?id=1281135

TylerH
  • 20,799
  • 66
  • 75
  • 101
1

Late to the party here, but I just encountered this problem as well in Firefox. Turns out it had to do with HOW the disabled attribute is applied to the stylesheet via Javascript.

See the below code, assuming some trigger to swap disabled state between two stylesheets. The first function is what I tried first, and the latter is what ended up working for me.

var myStyles = document.getElementById('my-default-style');
var myOtherStyles = document.getElementById('my-other-style');

function thisFailsInFirefox() {
  myStyles.setAttribute('disabled', true);
  myOtherStyles.removeAttribute('disabled');
}

function thisWorksInFirefox() {
  myStyles.disabled = true;
  myOtherStyles.disabled = false;
}

The thisWorksInFirefox function seemed to do the trick, maintaining functionality in Chrome / Safari / Edge, while making Firefox match in its behavior.

Adam
  • 254
  • 2
  • 13
0

Everything in your theme stylesheet could be prefixed with a class. For instance, if you have the following in your theme css:

h1 {color: red;}
h2 {color: green;}

It becomes something like:

.theme-white h1 {color: red;}
.theme-white h2 {color: green;}

Then, to toggle your theme, you can use the following:

if (show theme) {
    $('body').addClass('theme-white');
} else {
    $('body').removeClass('theme-white');
}
user1171848
  • 276
  • 3
  • 10
  • Certainly possible but this is a pretty big group of styles and not likely to be manageable. Right now I'm using LESS and my theme stylesheet simply imports my main styles and updates the variable values for the colors/sizes/etc of interest. I'm just very confused why firefox doesn't seem to adhere to the `disabled` tag on page load but does if you toggle it post-page load. – Gilman Aug 14 '13 at 20:59
  • 3
    Found this, which might explain why Firefox ignores the attribute: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link?redirectlocale=en-US&redirectslug=HTML%2FElement%2Flink#Attributes The "disabled" attribute is non-standard HTML, but it is valid via scripting. – user1171848 Aug 14 '13 at 21:26