it-swarm.it

Come eseguire il fallback al foglio di stile locale (non script) se la CDN non riesce

Mi sto collegando al foglio di stile jQuery Mobile su un CDN e vorrei tornare alla mia versione locale del foglio di stile se il CDN fallisce. Per gli script la soluzione è ben nota:

<!-- Load jQuery and jQuery mobile with fall back to local server -->
<script src="http://code.jquery.com/jquery-1.6.3.min.js"></script>
<script type="text/javascript">
  if (typeof jQuery == 'undefined') {
    document.write(unescape("%3Cscript src='jquery-1.6.3.min.js'%3E"));
  }
</script>

Vorrei fare qualcosa di simile per un foglio di stile:

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css" />

Non sono sicuro che si possa ottenere un approccio simile perché non sono sicuro che il browser si blocchi allo stesso modo quando si collega uno script come quando carica uno script (forse è possibile caricare un foglio di stile in un tag di script e quindi iniettarlo nella pagina)?

Quindi la mia domanda è: come posso garantire che un foglio di stile venga caricato localmente se un CDN fallisce?

102
ssn

Non testato su più browser, ma penso che funzionerà. Dovrà essere dopo aver caricato jquery, o dovrete riscriverlo in Javascript semplice.

<script type="text/javascript">
$.each(document.styleSheets, function(i,sheet){
  if(sheet.href=='http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css') {
    var rules = sheet.rules ? sheet.rules : sheet.cssRules;
    if (rules.length == 0) {
      $('<link rel="stylesheet" type="text/css" href="path/to/local/jquery.mobile-1.0b3.min.css" />').appendTo('head');
    }
 }
})
</script>
60
katy lavallee

Supponendo che tu stia utilizzando lo stesso CDN per css e jQuery, perché non fare un solo test e prenderlo tutto ??

<link href="//ajax.googleapis.com/ajax/libs/jqueryui/1/themes/start/jquery-ui.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script type="text/javascript">
    if (typeof jQuery == 'undefined') {
        document.write(unescape('%3Clink rel="stylesheet" type="text/css" href="../../Content/jquery-ui-1.8.16.custom.css" /%3E'));
        document.write(unescape('%3Cscript type="text/javascript" src="/jQuery/jquery-1.6.4.min.js" %3E%3C/script%3E'));
        document.write(unescape('%3Cscript type="text/javascript" src="/jQuery/jquery-ui-1.8.16.custom.min.js" %3E%3C/script%3E'));
    }
</script>
28
Mike Wills

Immagino che la domanda sia rilevare se un foglio di stile è caricato o meno. Un possibile approccio è il seguente:

1) Aggiungi una regola speciale alla fine del tuo file CSS, come:

#foo { display: none !important; }

2) Aggiungi il div corrispondente nel tuo HTML:

<div id="foo"></div>

3) Al documento pronto, controlla se #foo è visibile o no. Se il foglio di stile è stato caricato, non sarà visibile.

Demo qui - carica il tema della scorrevolezza di jquery-ui; nessuna regola viene aggiunta al foglio di stile.

27
Salman A

questo articolo suggerisce alcune soluzioni per bootstrap css http://eddmann.com/posts/providing-local-js-and-css-resources-for-cdn-fallbacks/

in alternativa, questo funziona per fontawesome

<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<script>
    (function($){
        var $span = $('<span class="fa" style="display:none"></span>').appendTo('body');
        if ($span.css('fontFamily') !== 'FontAwesome' ) {
            // Fallback Link
            $('head').append('<link href="/css/font-awesome.min.css" rel="stylesheet">');
        }
        $span.remove();
    })(jQuery);
</script>
7
dc2009

Ecco un'estensione della risposta di Katy Lavallee. Ho racchiuso tutto nella sintassi della funzione di auto-esecuzione per prevenire collisioni variabili. Ho anche reso lo script non specifico per un singolo collegamento. Ad esempio, ora qualsiasi collegamento al foglio di stile con un attributo url "fallback dati" verrà automaticamente analizzato. Non è necessario codificare gli URL in questo script come prima. Si noti che questo dovrebbe essere eseguito alla fine del <head> elemento anziché alla fine di <body> elemento, altrimenti potrebbe causare FOUC .

http://jsfiddle.net/skibulk/jnfgyrLt/

<link rel="stylesheet" type="text/css" href="broken-link.css" data-fallback="broken-link2.css">

.

(function($){
    var links = {};

    $( "link[data-fallback]" ).each( function( index, link ) {
        links[link.href] = link;
    });

    $.each( document.styleSheets, function(index, sheet) {
        if(links[sheet.href]) {
            var rules = sheet.rules ? sheet.rules : sheet.cssRules;
            if (rules.length == 0) {
                link = $(links[sheet.href]);
                link.attr( 'href', link.attr("data-fallback") );
            }
        }
    });
})(jQuery);
3
skibulk

È possibile potrebbe essere in grado di verificare l'esistenza del foglio di stile in document.styleSheets.

var rules = [];
if (document.styleSheets[1].cssRules)
    rules = document.styleSheets[i].cssRules
else if (document.styleSheets[i].rules)
    rule= document.styleSheets[i].rules

Prova qualcosa di specifico per il file CSS che stai utilizzando.

3
Stefan Kendall

Vuoi davvero seguire questa rotta javascript per caricare CSS nel caso in cui un CDN fallisca?

Non ho pensato a tutte le implicazioni sulle prestazioni, ma perderai il controllo di quando viene caricato il CSS e, in generale, per le prestazioni di caricamento della pagina, il CSS è la prima cosa che vuoi scaricare dopo l'HTML.

Perché non gestirlo a livello di infrastruttura: associa il tuo nome di dominio al CDN, assegnagli un breve TTL, monitora i file sul CDN (ad es. Usando Watchmouse o qualcos'altro), se il CDN fallisce, cambia il DNS in un sito di backup.

Altre opzioni che potrebbero essere utili sono "cache per sempre" sul contenuto statico, ma non esiste alcuna garanzia che il browser le manterrà naturalmente o utilizzando l'app-cache.

In realtà, come qualcuno ha detto in alto, se il tuo CDN è inaffidabile prendine uno nuovo

Andy

2
Andy Davies

Si potrebbe usare onerror per questo:

<link rel="stylesheet" href="cdn.css" onerror="this.onerror=null;this.href='local.css';" />

Il this.onerror=null; serve per evitare loop infiniti nel caso in cui il fallback stesso non sia disponibile. Ma potrebbe anche essere usato per avere fallback multipli.

Tuttavia, questo attualmente funziona solo su Firefox e Chrome.

2
Jan

Guarda queste funzioni:

$.ajax({
    url:'CSS URL HERE',
    type:'HEAD',
    error: function()
    {
        AddLocalCss();
    },
    success: function()
    {
        //file exists
    }
});

Ed ecco la versione JavaScript di Vanilla:

function UrlExists(url)
{
    var http = new XMLHttpRequest();
    http.open('HEAD', url, false);
    http.send();
    return http.status!=404;
}
if (!UrlExists('CSS URL HERE') {
AddLocalCss();
}

Ora la funzione effettiva:

function AddLocalCss(){
document.write('<link rel="stylesheet" type="text/css" href=" LOCAL CSS URL HERE">')
}

Assicurati solo che AddLocalCss sia chiamato in testa.

Puoi anche considerare di utilizzare uno dei seguenti modi spiegato in questa risposta :

Caricare utilizzando AJAX

$.get(myStylesLocation, function(css)
{
   $('<style type="text/css"></style>')
      .html(css)
      .appendTo("head");
});

Caricare usando creato dinamicamente

$('<link rel="stylesheet" type="text/css" href="'+myStylesLocation+'" >')
   .appendTo("head");
Load using dynamically-created <style>

$('<style type="text/css"></style>')
    .html('@import url("' + myStylesLocation + '")')
    .appendTo("head");

o

$('<style type="text/css">@import url("' + myStylesLocation + '")</style>')
    .appendTo("head");
1
user529649