web-dev-qa-db-ja.com

CDNが失敗した場合、ローカルスタイルシート(スクリプトではなく)にフォールバックする方法

CDN上のjQuery Mobileスタイルシートにリンクしていますが、CDNが失敗した場合、ローカルバージョンのスタイルシートにフォールバックしたいと思います。スクリプトの場合、ソリューションはよく知られています:

<!-- 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>

スタイルシートについても同様のことをしたいと思います:

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

スクリプトをロードするときと同じようにブラウザをブロックするかどうかわからないため、同様のアプローチが達成できるかどうかわかりません(スクリプトタグでスタイルシートをロードしてから、ページに挿入します)?

したがって、私の質問は次のとおりです。CDNが失敗した場合にスタイルシートがローカルにロードされるようにするにはどうすればよいですか。

102
ssn

クロスブラウザではテストされていませんが、これは機能すると思います。ただし、jqueryをロードした後でなければなりません。そうしないと、プレーンなJavascriptで書き直す必要があります。

<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

CssとjQueryに同じCDNを使用していると仮定して、1つのテストを行ってすべてをキャッチしないのはなぜですか?

<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

問題は、スタイルシートがロードされているかどうかを検出することだと思います。考えられるアプローチの1つは次のとおりです。

1)次のような特別なルールをCSSファイルの最後に追加します。

#foo { display: none !important; }

2)HTMLに対応するdivを追加します。

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

3)ドキュメントの準備ができたら、#fooが表示されるかどうか。スタイルシートがロードされている場合、表示されません。

ここにデモ -jquery-ui smoothnessテーマをロードします;スタイルシートにルールは追加されません。

27
Salman A

この記事では、bootstrap css http://eddmann.com/posts/providing-local-js-and-css-resources-for-cdn-fallbacks/

あるいは、これは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

Katy lavalleeの答えの拡張です。変数の衝突を防ぐために、すべてを自己実行関数の構文でラップしました。また、スクリプトを単一のリンクに対して非固有にしました。つまり、「data-fallback」url属性を持つスタイルシートリンクはすべて自動的に解析されます。以前のように、このスクリプトにURLをハードコーディングする必要はありません。これは、<head>要素の最後ではなく、<body>要素の最後で実行する必要があります。そうしないと、 [〜#〜] 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

mightdocument.styleSheetsのスタイルシートの存在をテストできます。

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

使用しているCSSファイルに固有のものをテストします。

3
Stefan Kendall

CDNに障害が発生した場合に、CSSをロードするためにこのjavascriptルートを本当に実行しますか?

すべてのパフォーマンスへの影響を考えたわけではありませんが、CSSがいつロードされるかを制御できなくなります。一般的に、ページのロードパフォーマンスについては、CSSはHTMLの後にダウンロードする最初のものです。

インフラストラクチャレベルでこれを処理しない理由-独自のドメイン名をCDNにマップし、短いTTLを与え、CDN上のファイルを監視します(たとえば、Watchmouseなどを使用して)、CDNが失敗した場合、DNSをバックアップサイトに変更します。

役立つ可能性のある他のオプションは、静的コンテンツの「永久キャッシュ」ですが、ブラウザがそれらをもちろん維持するか、アプリキャッシュを使用するという保証はありません。

実際に誰かがトップで言ったように、CDNが信頼できない場合は新しいCDNを入手してください

アンディ

2
Andy Davies

そのために onerror を使用できます。

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

this.onerror=null;は、フォールバック自体が利用できない場合に無限ループを回避することです。ただし、複数のフォールバックを使用することもできます。

ただし、これは現在FirefoxとChromeでのみ機能します。

2
Jan

これらの機能を見てください:

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

そして、ここにバニラJavaScriptバージョンがあります:

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

今、実際の機能:

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

AddLocalCssがヘッドで呼び出されることを確認してください。

また、次のいずれかの方法の使用を検討することもできます この回答で説明

AJAXを使用して読み込む

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

動的に作成されたものを使用してロードする

$('<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");

または

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