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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7383163/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 23:45:55  来源:igfitidea点击:

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

jqueryhtmljquery-mobilestylesheetcdn

提问by ssn

I am linking to the jQuery Mobile stylesheet on a CDN and would like to fall back to my local version of the stylesheet if the CDN fails. For scripts the solution is well known:

我正在链接到 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" />

I am not sure if a similar approach can be achieved because I am not sure whether the browser blocks in the same way when linking a script as it does when loading a script (maybe it is possible to load a stylesheet in a script tag and then inject it into the page) ?

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

So my question is: How do I ensure a stylesheet is loaded locally if a CDN fails ?

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

采纳答案by katy lavallee

Not cross-browser tested but I think this will work. Will have to be after you load jquery though, or you'll have to rewrite it in plain Javascript.

没有跨浏览器测试,但我认为这会奏效。但是必须在加载 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>

回答by Salman A

I guess the question is to detect whether a stylesheet is loaded or not. One possible approach is as follows:

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

1) Add a special rule to the end of your CSS file, like:

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

#foo { display: none !important; }

2) Add the corresponding div in your HTML:

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

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

3) On document ready, check whether #foois visible or not. If the stylesheet was loaded, it will not be visible.

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

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

Demo在这里——加载jquery-ui平滑主题;没有规则被添加到样式表。

回答by Mike Wills

Assuming you are using the same CDN for css and jQuery, why not just do one test and catch it all??

假设您对 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>

回答by dc2009

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

本文为 bootstrap css 提出了一些解决方案 http://eddmann.com/posts/providing-local-js-and-css-resources-for-cdn-fallbacks/

alternatively this works for fontawesome

或者这适用于 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>

回答by Stefan Kendall

You mightbe able to test for the existence of the stylesheet in document.styleSheets.

也许能够测试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

Test for something specific to the CSS file you're using.

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

回答by Jan Martin Keil

One could use onerrorfor that:

一个可以onerror用于:

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

The this.onerror=null;is to avoid endless loops in case the fallback it self is not available. But it could also be used to have multiple fallbacks.

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

However, this currently only works in Firefox and Chrome.

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

回答by skibulk

Here's an extension to katy lavallee's answer. I've wrapped everything in self-executing function syntax to prevent variable collisions. I've also made the script non-specific to a single link. I.E., now any stylesheet link with a "data-fallback" url attribute will automatically be parsed. You don't have to hard-code the urls into this script like before. Note that this should be run at the end of the <head>element rather than at the end of the <body>element, otherwise it could cause FOUC.

这是 katy lavallee 答案的扩展。我已将所有内容包装在自执行函数语法中以防止变量冲突。我还使脚本不特定于单个链接。IE,现在任何带有“data-fallback” url 属性的样式表链接都将被自动解析。您不必像以前一样将 url 硬编码到这个脚本中。请注意,这应该在<head>元素的末尾而不是在元素的末尾运行<body>,否则可能会导致FOUC

http://jsfiddle.net/skibulk/jnfgyrLt/

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

回答by Andy Davies

Do you really want to go down this javascript route to load CSS in case a CDN fails?

如果 CDN 失败,您真的想沿着这个 javascript 路线加载 CSS 吗?

I haven't thought all the performance implications through but you're going to lose control of when the CSS is loaded and in general for page load performance, CSS is the first thing you want to download after the HTML.

我还没有考虑所有的性能影响,但是您将失去对何时加载 CSS 的控制,一般来说,对于页面加载性能,CSS 是您在 HTML 之后想要下载的第一件事。

Why not handle this at the infrastructure level - map your own domain name to the CDN, give it a short TTL, monitor the files on the CDN (e.g. using Watchmouse or something else), if CDN fails, change the DNS to backup site.

为什么不在基础设施级别处理这个问题 - 将您自己的域名映射到 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.

其他可能有帮助的选项是在静态内容上“永久缓存”,但不能保证浏览器当然会保留它们或使用应用程序缓存。

In reality as someone said at the top, if your CDN is unreliable get a new one

实际上,正如有人在顶部所说的那样,如果您的 CDN 不可靠,请换一个新的

Andy

安迪

回答by Andy Davies

Look at these functions:

看看这些函数:

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

And here is vanilla JavaScript version:

这是香草 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();
}

Now the actual function:

现在实际功能:

function AddLocalCss(){
document.write('<link rel="stylesheet" type="text/css" href=" LOCAL CSS URL HERE">')
}

Just make sure AddLocalCss is called in the head.

只需确保在头部调用 AddLocalCss 即可。

You might also consider using one of the following ways explained in this answer:

您也可以考虑使用本答案中解释的以下方法之一

Load using AJAX

使用 AJAX 加载

$.get(myStylesLocation, function(css)
{
   $('<style type="text/css"></style>')
      .html(css)
      .appendTo("head");
});

Load using dynamically-created

使用动态创建的加载

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

or

或者

$('<style type="text/css">@import url("' + myStylesLocation + '")</style>')
    .appendTo("head");

回答by Ben Schwarz

I'd probably use something like yepnope.js

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

Taken from the readme.

取自自述文件。