如果CDN失败,如何回退到本地样式表(而不是脚本)

时间:2011-09-12 03:56:58

标签: jquery html jquery-mobile stylesheet 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失败,如何确保本地加载样式表?

11 个答案:

答案 0 :(得分:59)

没有跨浏览器测试,但我认为这将有效。你必须在加载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 :(得分:28)

假设您正在为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>

答案 2 :(得分:27)

我想问题是检测样式表是否已加载。一种可能的方法如下:

1)在CSS文件的末尾添加一个特殊规则,例如:

#foo { display: none !important; }

2)在HTML中添加相应的div:

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

3)在准备好文档时,检查#foo是否可见。如果加载了样式表,则它将不可见。

Demo here - 加载jquery-ui平滑主题;没有规则添加到样式表。

答案 3 :(得分:7)

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

答案 4 :(得分:3)

可能能够在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文件的特定内容。

答案 5 :(得分:3)

这是katy lavallee回答的扩展。我已将所有内容都包含在自执行函数语法中以防止可变冲突。我还使脚本非特定于单个链接。 I.E.,现在任何带有“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);

答案 6 :(得分:2)

你真的想在这个javascript路由下加载CSS以防CDN失败吗?

我没有想到所有的性能影响,但是你将失去对CSS加载时的控制,并且通常对于页面加载性能,CSS是你想要在HTML之后下载的第一件事。

为什么不在基础设施层面处理这个问题 - 将您自己的域名映射到CDN,给它一个简短的TTL,监控CDN上的文件(例如使用Watchmouse或其他东西),如果CDN失败,请将DNS更改为备份站点。

其他可能有用的选项是静态内容“永远缓存”,但无法保证浏览器会保留它们或使用app-cache。

实际上,有人在顶部说,如果你的CDN不可靠,那就得到一个新的

安迪

答案 7 :(得分:2)

一个人可以使用onerror

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

this.onerror=null;可以避免无限循环,以防其自身无法使用后备。但是它也可以用于具有多个后备。

但是,当前仅在Firefox和Chrome中有效。

答案 8 :(得分:1)

看看这些功能:

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

这是vanilla 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。

您也可以考虑使用以下方式之一explained in this answer

使用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");

答案 9 :(得分:-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');
    }
  }
}]);

取自the readme.

答案 10 :(得分:-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>