簡體   English   中英

如果 CDN 失敗,如何回退到本地樣式表(不是腳本)

[英]How to fallback to local stylesheet (not script) if CDN fails

我正在鏈接到 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 失敗,我如何確保在本地加載樣式表?

沒有跨瀏覽器測試,但我認為這會奏效。 但是必須在加載 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>

可以為此使用onerror

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

this.onerror=null; 是為了避免在回退本身不可用的情況下無限循環。 但它也可以用於有多個回退。

但是,這目前僅適用於 Firefox 和 Chrome。

更新:同時,這似乎得到所有常見瀏覽器的支持

我想問題是要檢測是否加載了樣式表。 一種可能的方法如下:

1) 在 CSS 文件的末尾添加一條特殊規則,例如:

#foo { display: none !important; }

2)在你的HTML中添加相應的div:

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

3) 文件准備好后,檢查#foo是否可見。 如果加載了樣式表,它將不可見。

Demo here -- 加載jquery-ui平滑主題; 沒有規則被添加到樣式表。

假設您對 css 和 jQuery 使用相同的 CDN,為什么不做一個測試並全部捕獲?

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

本文為 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>

也許能測試在樣式表的存在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 文件的內容。

這是 katy lavallee 答案的擴展。 我已將所有內容包裝在自執行函數語法中以防止變量沖突。 我還使腳本不特定於單個鏈接。 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);

如果 CDN 失敗,您真的想沿着這個 javascript 路線加載 CSS 嗎?

我還沒有考慮所有的性能影響,但是您將失去對何時加載 CSS 的控制,一般來說,對於頁面加載性能,CSS 是您在 HTML 之后想要下載的第一件事。

為什么不在基礎設施級別處理這個問題 - 將您自己的域名映射到 CDN,給它一個短的 TTL,監視 CDN 上的文件(例如使用 Watchmouse 或其他東西),如果 CDN 失敗,將 DNS 更改為備份站點。

其他可能有幫助的選項是在靜態內容上“永久緩存”,但不能保證瀏覽器當然會保留它們或使用應用程序緩存。

實際上,正如有人在頂部所說的那樣,如果您的 CDN 不可靠,請換一個新的

安迪

看看這些函數:

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

我可能會使用類似 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');
    }
  }
}]);

取自自述文件。

//(load your cdn lib here first)

<script>window.jQuery || document.write("<script src='//me.com/path/jquery-1.x.min.js'>\x3C/script>")</script>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM