How to create a fallback when importing CSS files?

Asked

Viewed 355 times

12

In How I should work on Bootstrap and Javascript links?, about how to serve the media files, whether via CDN server or local server, it was answered that it is interesting to keep both: initially loading the file from CDN and, in case of failure, having a fallback on the local server, as it is done with jQuery:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="/js/jquery-1.10.2.min.js"><\/script>')</script>

With Javascript files, create this fallback is trivial, because it is enough to verify the existence of the object, as in window.jQuery || ..., but with other files such as CSS and images, this is not so trivial.

So how is it possible to define a fallback for importing CSS files?

The idea would be to have as a result something similar to:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script>bootstrapLoaded || document.write('<link rel="stylesheet" href="assets/css/bootstrap/3.3.7/css/bootstrap.min.css">')</script>

What does the term Fallback mean?

  • In the case of Bootstrap particularly you can do the same with jQuery, only searching for some method used in Bootstrap JS. If this Bootstrap JS fails, probably the CSS CDN will also fail, ai vc already calls the failed JS and CSS too! This option is not exclusively for qq CSS, but works for Bootstrap and other frameworks that have JS and CSS in the same CDN. If it is not clear tell me that cake an answer with more details.

  • Which browsers do you want to support? The option to load all scripts dynamically is valid or do you even want fallbacks for static HTML scripts?

  • @Sergio dynamic loading is valid. If there are pros/cons, it would be nice to list them.

2 answers

3


According to the MDN documentation you can use the event onerror on the tag link that loads the CSS. If there is a failure to load the file, you can call a Javascript function in the event:

                                                     evento     chama a função
                                                        ↓             ↓
<link rel="stylesheet" href="//...arquivoRemoto.css" onerror="cssNaoCarregado()" />

In the function, you enter the head from page to tag <link> with the local archive:

<script>
function cssNaoCarregado(){
   var css = document.createElement("link");
   css.rel = "stylesheet";
   css.href = "arquivoLocal.css";
   document.querySelector("head").appendChild(css);
}
</script>

Note: does not work in Microsoft browsers. In these browsers, even if the file has not been loaded, it calls the event onload (<link rel="stylesheet" onload="função()"...>), as if it had been loaded.

3

Tests the number of css rules chosen, The script I leave below only tests a css if it has been loaded, it is up to you to test more than one create an object array with the external css path you want to test and the related local css, and scroll through it for testing one by one. Ex:

var cssTestar = [{externo: "caminhoexterno", local: "caminholocal"},{externo: "caminhoexterno", local: "caminholocal"}];

I recommend placing the following javascript block as the last head element;

<script type="text/javascript">
    for (var i = 0; i < document.styleSheets.length; i++) {
        var sheet = document.styleSheets[i];
        if (!sheet.href) {
            continue;
        }
        if(sheet.href=='https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrapnaoexiste.min.css') {
            var qtdRules = 0;
            try {
                var rules = sheet.hasOwnProperty("rules") && sheet.rules ? sheet.rules : (sheet.hasOwnProperty("cssRules") ? sheet.cssRules : []);
                qtdRules = rules.length;
            } finally {
                if (qtdRules == 0) {
                    var link = document.createElement('link');
                    link.id = 'id';
                    link.rel = 'stylesheet';
                    link.type = "text/css";
                    link.href = "caminholocal/seucsslocal.css";
                    document.head.appendChild(link);
                }
            }
        }
    }
</script>

Example in snippet: Obs.: when executing does not show anything in the result frame but if inspecting it will see the link tag with the "csslocal" created in head;

<!DOCTYPE html>
<html>
<head>
	<title>teste</title>
	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrapnaoexiste.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">

<script type="text/javascript">
	for (var i = 0; i < document.styleSheets.length; i++) {
		var sheet = document.styleSheets[i];
	    if (!sheet.href) {
	        continue;
	    }
	  	if(sheet.href=='https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrapnaoexiste.min.css') {
		  	var qtdRules = 0;
		    try {
				var rules = sheet.hasOwnProperty("rules") && sheet.rules ? sheet.rules : (sheet.hasOwnProperty("cssRules") ? sheet.cssRules : []);
				qtdRules = rules.length;
			} finally {
				if (qtdRules == 0) {
					var link = document.createElement('link');
				    link.id = 'id';
				    link.rel = 'stylesheet';
				    link.type = "text/css";
				    link.href = "caminholocal/seucsslocal.css";
				    document.head.appendChild(link);
				}
			}
		}
	}
</script>
</head>
<body>
</body>
</html>

Browser other questions tagged

You are not signed in. Login or sign up in order to post.