Another way to load CSS through RequireJS

In the process of developing JS modules claiming to be reusable, often there is a need to load a file with styles besides js-code and markup. As you know, styles themselves can be added to a document in three ways: through the link tag, through the style tag, and through the style attribute. Depending on the selected method, you can get various pros and cons. I suggest looking at the method consisting of using the link tag, but eliminated the problem of the absence of the end event of loading the stylesheet from the browser.

for those who only have a code
define(["text!myCSS.css"], function(cssText) {
	'use strict';
	var link = document.createElement("link");
	link.rel = "stylesheet";
	link.type = "text/css"
	link.href = "data:text/css,"+encodeURI(cssText);
	var cssLinks = document.querySelectorAll("link[rel=stylesheet]");
	if (cssLinks.length > 0) {
		cssLinks[0].parentElement.insertBefore(link, cssLinks[0]);
	} else {
		document.querySelector("head").appendChild(link);
	}
});


Let's start with the answer to the question “Why exactly through the link tag?”

The fact is that the module usually wants to be able to conveniently customize its visual presentation.
If we want to use the style attribute directly in our markup, then later on when reusing we will have to somehow change these attributes - it’s super inconvenient and not flexible.

If we want to use the style tag, then the problem arises that in order to customize such styles, you also have to insert the style tag with the necessary content into the document, which is also not very convenient.

If we want to use the link tag, then we can simply connect our own stylesheet after the loaded one and adjust the default view for immediate needs.

It follows from the above that the option with the link tag is the most flexible, because allows you to override styles when using the component in the largest number of ways.

As written in the RequireJS documentation, you can use the following code to load css:

function loadCss(url) {
    var link = document.createElement("link");
    link.type = "text/css";
    link.rel = "stylesheet";
    link.href = url;
    document.getElementsByTagName("head")[0].appendChild(link);
}

It is not bad for everyone, except that you don’t know when exactly your css will be loaded (and whether it will be at all, could, for example, be sealed in ways). This problem is also fraught with the fact that it can cause ugly behavior of the picture if the page is rendered before the file is downloaded.

And I want to write a component something like this:

define(["text!myCSS.css", "text!myHTML.html"], function(cssText, htmlText) {
	'use strict';
...
});

But how then to cram the resulting css text into our page? The style tag could help us, but earlier it was decided that our option is link.

The proposed solution is a Data URL (if anyone does not know what it is, you can see it here ).

We will add something like this:

	var link = document.createElement("link");
	link.rel = "stylesheet";
	link.type = "text/css"
	link.href = "data:text/css,"+encodeURI(cssText);
	var cssLinks = document.querySelectorAll("link[rel=stylesheet]");
	if (cssLinks.length > 0) {
		cssLinks[0].parentElement.insertBefore(link, cssLinks[0]);
	} else {
		document.querySelector("head").appendChild(link);
	}

The method undoubtedly has some disadvantages, of the obvious - base64 encoding increases the amount of data, theoretically, you can encounter restrictions on the length of the URL for some browsers. But if the volume of styles is small, then the method looks quite working.

UPD:
Thank oledje for the tip, the base64 encoding of the text is not necessary, it is better suited URL encoding, corrected code.

Also popular now: