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>

I would like to do something similar for a style sheet:

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

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

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

35051 次浏览

看看这些功能:

$.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 即可。

您也可以考虑使用以下方法之一 在这个答案中解释:

Load using 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");

也许吧能够测试 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 文件的特定内容。

没有跨浏览器测试,但我认为这将工作。必须在加载 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) Add a special rule to the end of your CSS file, like:

#foo { display: none !important; }

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

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

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

Demo here -- loads jquery-ui smoothness theme; no rule is added to stylesheet.

我可能会用 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');
}
}
}]);

取自 自述。

您真的希望在 CDN 失败的情况下通过这种 javascript 路由来加载 CSS 吗?

我还没有考虑到所有的性能影响,但是您将失去对何时加载 CSS 的控制,通常对于页面加载性能而言,CSS 是您在 HTML 之后首先要下载的内容。

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

Other options that might help are "cache forever" on static content but there's no guarantee the browser will keep them of course or using the app-cache.

实际上,正如有人在高层所说,如果你的 CDN 不可靠,就换一个新的

安迪

假设您正在对 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>
//(load your cdn lib here first)


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

这是 Katy Lavallee 答案的延伸。为了防止变量冲突,我将所有内容都包装在自执行函数语法中。我还将脚本设置为非特定于单个链接。也就是说,现在任何带有“ data-falback”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);

this article suggests some solutions for the bootstrap css Http://eddmann.com/posts/providing-local-js-and-css-resources-for-cdn-fallbacks/

或者,这对 Fontawome 也有效

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

我们可以使用 onerror:

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

this.onerror=null;是为了避免没完没了的循环,以防它自己的备份不可用。但是它也可以用来进行多重备份。

然而,目前这只能在 Firefox 和 Chrome 中使用。

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