【问题标题】:Check external stylesheet has loaded for fallback检查外部样式表是否已加载以备后备
【发布时间】:2013-07-16 01:54:23
【问题描述】:

有一个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].rules 也是 null。我不确定我是否在控制台中正确访问它,也许还有另一个我应该使用或反对的功能?

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

如果有人能帮我找到如何检查样式表是否已加载,那将非常有帮助,非常感谢。

【问题讨论】:

  • 好吧,在您的情况下,您想知道工作表是否实际加载,而您链接到的帖子只是处理在标题中放置一个 (如果一个尚不存在)。不幸的是,如果 元素已完成加载,即使您通过 JS 创建它,也无法通过 Javascript 检查。我确实想出了这个:blog.rjzaworski.com/2011/08/… 这有点骇人听闻,但简而言之,它涉及在页面上放置一个元素,一旦加载 CSS,其属性就会改变,然后每隔一段时间检查它。
  • @Brian 谢谢你,这是一个有趣的方法。我认为您应该将此添加为答案,以便我(和其他人)至少可以为您提供一些帮助。你太谦虚了:)
  • 这不是一个完整的解决方案,因为实际上没有任何方法可以知道 CSS 何时完成加载到浏览器。所以你必须设置一个有点随意的“超时”时间,然后你决定使用你的后备 CSS。无论如何,这类问题通常通过负载均衡器和 CDN 来处理,而不是通过前端的 JS 代码来处理。我认为我在这里所做的贡献不足以提供作为“答案”本身的“答案”,而只是您可能希望使用 JS 代码解决这个问题的大方向;)
  • @Brian 我终于让它工作了,使用了你博客文章中想法的一个版本。非常感谢,我真的很感激。

标签: javascript jquery css


【解决方案1】:

注意:

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

什么有效

非常感谢 cmets 中的 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>

这也不起作用,因为某些(全部?)浏览器会阻止对外部样式表添加的规则的访问。

【讨论】:

  • 谢谢!为什么要使用元标记而不是在正文中添加隐藏的 div?
  • @Sean 如果有一个很好的理由,我现在不记得了!我很确定最近这个问题已经以更好的方式解决了,我看到几个库管理它。我也不记得在哪里……我的大脑正在慢慢融化(应该如此:)
  • 我想我明白了。大多数 CSS 文件都包含在头部的链接元素中。如果您的脚本检查它是否在此之后立即加载,因为它在头部的上下文中,所以身体还没有被加载到 DOM 中。所以 document.body 实际上给你一个 null ref 错误。
  • 感谢@Sean,您应该真的能够获得该评论的代表。出色的侦探工作应该得到奖励!
  • 谢谢@iain。我编辑了答案以包含它。不确定我是否会因此获得任何街头信誉。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-14
  • 1970-01-01
  • 2011-09-23
  • 1970-01-01
  • 2011-05-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多