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

ssn*_*ssn 105 html jquery cdn stylesheet jquery-mobile

我正在链接到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>
Run Code Online (Sandbox Code Playgroud)

我想为样式表做类似的事情:

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css" />
Run Code Online (Sandbox Code Playgroud)

我不确定是否可以实现类似的方法,因为我不确定浏览器在链接脚本时是否以与加载脚本时相同的方式阻塞(也许可以在脚本标记中加载样式表然后把它注入页面)?

所以我的问题是:如果CDN失败,如何确保本地加载样式表?

kat*_*lee 61

没有跨浏览器测试,但我认为这将有效.你必须在加载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>
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案并不适用于所有CDN /样式表,例如来自bootstrapcdn.com的`CSSStyleSheet` js对象在浏览器中都有空的`rules`和`cssRules`字段(Chrome 31).**UPD**:它实际上可能是一个跨域问题,答案中的css文件对我来说也不起作用. (8认同)
  • 这也是使用`onerror`事件的好方法.http://stackoverflow.com/questions/30546795/how-to-detect-when-one-or-more-js-css-library-fail-to-load-eg-cdn/#answer-30547720 (3认同)
  • 对于http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css,我得到rules = null,即使它已正确加载.我使用的是Chrome 26,我认为这是因为脚本是跨域的? (2认同)
  • 它适用于从其他域加载的CSS吗?不,你不能枚举外部样式表的`.rules` /`.cssRules`.http://jsfiddle.net/E6yYN/13/ (2认同)

Jan*_*eil 39

一个可以onerror用于:

<link rel="stylesheet" href="cdn.css" onerror="this.onerror=null;this.href='local.css';" />
Run Code Online (Sandbox Code Playgroud)

this.onerror=null;是为了避免无限循环,以防万一回退本身不可用。但它也可以用于有多个回退。

但是,这目前仅适用于 Firefox 和 Chrome。

更新:同时,这似乎被所有常见浏览器支持

  • 恭喜你们所有人,像我一样,无法相信早期答案中提出的复杂方案仍然是最好的方法,并一路走到了这里。这半个衬里效果非常好。让我们看看我们能以多快的速度将其推到首位。或者,具有版主访问权限的人可以删除旧答案。 (11认同)

Mik*_*lls 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>
Run Code Online (Sandbox Code Playgroud)

  • -1`为什么不做一次测试并抓住它?` - 因为有一百万个理由可能会失败,其他人会成功. (5认同)
  • @JackTuck:解析器无法区分JS字符串中的`<script>`和外部发现的字符串.这就是为什么在为CDN回退写出标签时也会看到`<\/script>`的原因. (2认同)

Sal*_*n A 27

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

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

#foo { display: none !important; }
Run Code Online (Sandbox Code Playgroud)

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

<div id="foo"></div>
Run Code Online (Sandbox Code Playgroud)

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

在这里演示 - 加载jquery-ui平滑主题; 没有规则添加到样式表.

  • +1是一个聪明的解决方案.唯一的问题是,人们通常不能去并在某人的CDN上托管的样式表的末尾添加一行 (37认同)
  • 不幸的是,我们无法输入我们自己的类到CDN文件.也许我们可以尝试利用已存在的那个. (2认同)
  • 注意:您没有_really_必须向外部CSS添加新规则.只需使用其行为已知的现有规则.在我的演示中,我使用ui-helper-hidden类,它应该隐藏元素,然后检查元素是否在页面加载时隐藏. (2认同)

dc2*_*009 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>
Run Code Online (Sandbox Code Playgroud)


Ste*_*all 5

也许能够测试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
Run Code Online (Sandbox Code Playgroud)

测试特定于您正在使用的 CSS 文件的内容。