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


108

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が失敗した場合にスタイルシートがローカルに読み込まれるようにするにはどうすればよいですか?


2
これも可能かどうか知りたいのですが... CDNがダウンしていることについて本当に悩んでいる場合は、ローカルホスティングを使用します。
Fosco、2011

2
@Stefan Kendallさん、彼のサイトはCDNよりもダウンする可能性が高いというのが正しい記述だと思います
Shawn Mclean

回答:


63

クロスブラウザはテストされていませんが、これはうまくいくと思います。ただし、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>

良い解決策、それが対処しない1つの問題は、CDNがロードするには遅すぎる場合です...おそらく何らかのタイムアウトですか?
GeorgeU、2011

2
code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css、私はそれが正しくロードされていたとしても、ルール=ヌルを取得します。Chrome 26を使用していますが、それはスクリプトがクロスドメインであるためだと思いますか?
simplfuzz 2013

8
このソリューションは、実際にはすべてのCDN /スタイルシートに対して機能しません。たとえばCSSStyleSheet、bootstrapcdn.comからのjsオブジェクトはすべて、ブラウザー(Chrome 31)に空のフィールドがrulesありcssRulesます。UPD:実際にはクロスドメインの問題である可能性があります。回答のcssファイルも機能しません。
Maksim Vi。

3
これもonerrorイベントを使った良い解決策です。stackoverflow.com/questions/30546795/…–
ケミカルプログラマー、

2
別のドメインから読み込まれたCSSで動作しますか?いいえ、外部スタイルシートの.rules/ .cssRulesを列挙することはできません。jsfiddle.net/E6yYN/13
Salman A

29

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

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

#foo { display: none !important; }

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

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

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

ここでのデモ -jquery-uiの滑らかさのテーマを読み込みます。スタイルシートにルールは追加されません。


42
+1は賢いソリューションです。唯一の問題は、誰かがCDNでホストされているスタイルシートの最後に通常行を追加して行を追加できないことです
Jannie Theunissen

2
残念ながら、CDNファイルに独自のクラスを入力することはできません。すでにあるものを活用してみようかな。
2014年

1
私はこれがとても好きです、ありがとう。本当にパワフルです。もちろん、私は、CDNスタイルシートを操作することはできませんが、私は、彼らが表示されている場合、私はショーのチェックにコードを修正したので、クラスが使用されているものを知っている-確かに非常に巧妙な:)
Nosnibor

3
注意:外部CSSに新しいルールを追加する必要はありませ。動作がわかっている既存のルールを使用するだけです。私のデモでは、要素を非表示にするはずのui-helper-hiddenクラスを使用しています。次に、ページの読み込み時に要素が非表示になるかどうかを確認します。
Salman A

28

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>

1
エスケープされていない文字列を最初に使用する際の問題は何document.write("<script type='text/javascript' src='path/to/file.js'>")ですか?
Jack Tuck

2
@JackTuck:パーサーは<script>、JS文字列の内部と外部で見つかった文字列を区別できません。これが<\/script>、CDNフォールバックのタグを書き出すときにもよく見られる理由です。
ブラッドクリスティ

6
-1- why not just do one test and catch it all?失敗する理由は100万あり、他の人は成功するため。
Flimzy 2015年

7

この記事は、ブートストラップ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="https://stackoverflow.com/css/font-awesome.min.css" rel="stylesheet">');
        }
        $span.remove();
    })(jQuery);
</script>

これをFont Awesome 5で使用したい場合は、(FontAwesome)を(if句で)「Font Awesome 5 Free」(フリーフォントを使用している場合)に変更します。それ以外の場合は、正常に動作するはずです。
ジェイソンクラーク

4

あなたは可能性がある中、スタイルシートが存在するかどうかをテストすることができます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

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


4

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

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

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

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


3

これがケイティ・ラヴァリーの答えの拡張です。変数の衝突を防ぐために、すべてを自己実行関数構文にラップしました。また、スクリプトを1つのリンクに限定しないようにしました。IE、 "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);

1
カプセル化は好きですが、一般に、クロスドメインスタイルシートのsheet.rulesを検査することはできません。この一般的な考え方は引き続き使用できますが、別のチェックを行う必要があります。
John Vinopal、2015

document.styleSheets[i].ownerNode.datasetあなたがアクセスできる<link data-* />属性
アルウィンケスラー

2

CDNが失敗した場合にCSSをロードするために、このJavaScriptルートを本当にダウンしますか?

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

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

役立つ可能性のある他のオプションは、静的コンテンツで「永久にキャッシュ」することですが、ブラウザーがそれらをもちろん保持したり、app-cacheを使用したりする保証はありません。

実際、誰かが上で言ったように、あなたのCDNが信頼できない場合、新しいものを取得します

アンディ


7
CDNは信頼できますが、開発環境のインターネット接続は信頼できません;)
砕氷船2013年

1

これらの関数を見てください:

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

はい、少なくとも最新のブラウザでは、IE6についてはわかりません。

全部をダウンロードする代わりに、単にチェックする方法はありますか?
Shawn Mclean

OP要求を行う唯一の考えられる理由は、過剰なネットワークトラフィックを回避することです。これにより、過剰なネットワークトラフィックが発生します。
Stefan Kendall、

@stefan Kendall:いいえ、それは彼がファイルが確実に読み込まれるようにしたくない理由でもありません。

それだけが問題である場合は、CDNを使用しないでください。ヘッダーだけをテストする方が良いですが、ほとんどのCDNとブラウザーがXSSを許可しないと確信しています。
Stefan Kendall

-1

私はおそらくyepnope.jsのようなものを使うでしょう

yepnope([{
  load: 'http:/­/ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js',
  complete: function () {
    if (!window.jQuery) {
      yepnope('local/jquery.min.js');
    }
  }
}]);

Readmeから取得。


10
@BenSchwarz、それはあなたが尋ねられた質問に決して答えない無関係なコードを貼り付けることができることを意味しません。
AlicanC 2013年

-8
//(load your cdn lib here first)

<script>window.jQuery || document.write("<script src='//me.com/path/jquery-1.x.min.js'>\x3C/script>")</script>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.