检查外部样式表是否已加载后备

时间:2013-07-16 01:54:24

标签: javascript jquery css

有一个similar post already,但我觉得它不能很好地回答我的特定问题。

我想检查外部样式表是否已加载。例如,如果它已被网络问题阻碍,那么我想知道并加载回退。这是对于jQuery的主题CSS 的CDN的后备,但我更喜欢这不是特定于那个,因为我使用的其他外部CSS我想申请这也是。

  • 引用link元素将出现在页面上,因此不能接受头部中链接元素存在的模式匹配。
  • 我无法更改样式表中的CSS,因此无法添加虚拟CSS。
  • 由于我无法控制外部样式表中的CSS,因此依赖CSS中的现有类是脆弱的,所以我更倾向于是否有其他解决方案。
  • 使用超时是唯一的方法吗?我应该为它设置多长时间?我应该选择什么样的事件来衡量时间?
  • 我更喜欢纯javascript,然后是jQuery,但是其他javascript框架的答案将被接受,因为它们无疑会对某人有所帮助。

编辑:一个新想法。如果通过AJAX加载样式表并检查状态代码怎么样?这是一个可行的选择,有人知道吗?


这是我目前的脚本:

<script type="text/javascript">
  var cdn = 'http://code.jquery.com/ui/1.10.1/themes/black-tie/jquery-ui.min.css';
  var ss = document.styleSheets;
  for (var i = 0, max = ss.length; i < max; i++) {
    var sheet = ss[i];
    var rules = sheet.rules ? sheet.rules : sheet.cssRules;
    if (sheet.href == cdn) {
      if ( rules == null || rules.length == 0) {
        var link = document.createElement("link");
        link.rel = "stylesheet";      
        link.href = '/js/jquery-ui/1.10.1/themes/black-tie/jquery-ui.min.css';
        document.getElementsByTagName("head")[0].appendChild(link);  
      }
      break;
    }  
  }
</script>

我在使用控制台(Chrome v25.0.1364.172)时发现,即使样式表已从CDN加载,document.styleSheets[x].rulesnull。我不确定我是否在控制台中正确访问它,也许我应该使用另一个功能或对象?

CSSStyleSheet {rules: null, cssRules: null, ownerRule: null, media: MediaList, title: null…}
cssRules: null
disabled: false
href: "http://code.jquery.com/ui/1.10.1/themes/black-tie/jquery-ui.min.css"
media: MediaList
ownerNode: link
ownerRule: null
parentStyleSheet: null
rules: null
title: null
type: "text/css"
__proto__: CSSStyleSheet

如果有人可以帮我找到如何检查样式表已加载,那将非常有用并且非常感激。

1 个答案:

答案 0 :(得分:5)

注意:

请参阅the github repo for the rack-jquery_ui-themes library处的生产代码。忽略所有常量的插值和像:THEME这样的大写符号,它们在其他地方被替换。想象一下它原始的javascript。

工作原理

非常感谢Brian在我的问题评论中为此提供了主要的灵感来源。

<meta id='rack-jquery-ui-themes-fallback-beacon' />
<script type="text/javascript">
  var meta = $("#rack-jquery-ui-themes-fallback-beacon");
  meta.addClass("ui-icon");
  if ( meta.css('width') != "16px" ) {
    $('<link rel="stylesheet" type="text/css" href="/js/jquery-ui/#{JQueryUI::JQUERY_UI_VERSION}/themes/:THEME/#{JQUERY_UI_THEME_FILE}" />').appendTo('head');
  }
  meta.remove();
</script>

添加元标记然后应用jQuery UI样式表中的CSS类,然后检查它已更改并添加后备链接,如果没有,然后删除元标记。

我们在头部使用元标记的原因,而不是像身体中的div那样的东西。大多数CSS文件都包含在头部的链接元素中。如果检查它是否加载的脚本在此之后立即出现,因为它位于头部的上下文中,所以尚未将主体加载到DOM中。在该上下文中访问document.body将导致null ref错误。

什么没有用

使用AJAX发出HEAD请求并检查状态:

<script type="text/javascript">
  $.ajax({
    type: "HEAD",
    url: ':CDNURL',
    success: function(css,status) {
      // do nothing
    },
    error: function(xhr,status,error) {
      var link = document.createElement("link");
      link.rel = "stylesheet";     
      link.href = ':FALLBACK_URL';
      document.getElementsByTagName("head")[0].appendChild(link); 
    }
  });
</script>

我发现this is a potential security threat因此浏览器不会允许它。

检查DOM的样式表规则:

<script type="text/javascript">
  var has_jquery_rules = false;
  var i = document.styleSheets.length - 1;
  while (i >= 0 ) {
    var sheet = document.styleSheets[i];
    if(sheet.href == ":CDNURL/ui/#{JQueryUI::JQUERY_UI_VERSION}/themes/:THEME/jquery-ui.min.css") {
      var rules = sheet.rules ? sheet.rules : sheet.cssRules;
      has_jquery_rules = rules.length == 0 ? false : true;
      break; // end the loop.
    }
    has_jquery_rules = false;
    i--;
  }
  if ( has_jquery_rules == false ) {
    $('<link rel="stylesheet" type="text/css" href="/js/jquery-ui/#{JQueryUI::JQUERY_UI_VERSION}/themes/:THEME/#{JQUERY_UI_THEME_FILE}" />').appendTo('head');
  }
</script>

这也行不通,因为一些(所有?)浏览器阻止访问外部样式表添加的规则。