11

在 Code.org 的 App Lab 编辑器中,我们最近开始在 Chrome 64 中看到这个错误:

Uncaught DOMException: Failed to read the 'rules' property from 'CSSStyleSheet'

在这个函数中抛出错误,该函数旨在检测浏览器是否正在使用 CSS 媒体查询,在包含styleSheets[i].cssRules.

/**
 * IE9 throws an exception when trying to access the media field of a stylesheet
 */
export function browserSupportsCssMedia() {
  var styleSheets = document.styleSheets;
  for (var i = 0; i < styleSheets.length; i++) {
    var rules = styleSheets[i].cssRules || styleSheets[i].rules;
    try {
      if (rules.length > 0) {
        // see if we can access media
        rules[0].media;
      }
    } catch (e) {
      return false;
    }
  }
  return true;
}

该问题已在 Windows、OSX、Ubuntu 和 ChromeOS 上发现;在 Chrome 版本 64.0.3282.167 和 64.0.3282.186 上。然而,我们也发现这个问题并没有发生在完全相同的 Chrome 版本和平台上——而且我们似乎无法在隐身窗口中重现该问题。

这个错误的根本原因是什么?

4

3 回答 3

22

对于 Web 开发人员来说,这是一个好故事和一个新的“陷阱”,所以我只需要分享:

Chrome 64.0.3282.0(2018 年 1 月发布,完整更改列表)引入了对样式表安全规则的更改。我很恼火,因为我在任何更改日志中都找不到比完整提交列表详细的更改。

Chromium 中的提交a4ebe08描述:

更新 CSSStyleSheet 的行为以匹配安全来源的规范

规范在这里: https ://www.w3.org/TR/cssom-1/#the-cssstylesheet-interface

更新:如果样式表不可访问,以下方法现在会引发 SecurityError:

  • cssRules() / 规则()
  • 插入规则()
  • 删除规则()

此提交是对错误安全性的修复:关于 CSS 和链接元素的 CORS 实现不一致。链接的 W3C 规范详细描述了使用 CSS 对象模型需要同源访问的地方。

说了这么多,为什么这个问题会出现在 App Lab 中?我们不应该遇到任何 CORS 问题,因为我们只从我们自己的来源加载样式表:

显示从受影响页面请求的所有 CSS 的 Chrome 网络标签

最后的线索是我们无法在私人标签中重现此问题。我们开始查看 Chrome 扩展并意识到一些受影响的用户启用了Loom Video Recorder扩展,这似乎将自己的 CSS 注入到页面中。由于我们的 (naïve) 函数正在遍历所有加载的样式表,它试图访问由扩展注入的样式表,从而导致 CORS 错误。

也就是说,围绕 Chrome 中的这一变化仍有一些未解决的问题和争论:

  • 这条对原始安全错误的评论抱怨说,现在检测样式表无法从 JavaScript 访问的唯一方法是使用try/catch.
  • 1 月 23 日打开的 Chromium 错误(document.styleSheets.cssRules 为 null 即使使用 Access-Control-Allow-Origin: *)表明新的安全规则可能存在实施问题,会破坏某些变通方法。
  • 正在实施的规范看起来相当稳定,但它仍然处于“工作草案”状态,所以谁知道它将在哪里登陆以及其他浏览器将实施什么。

为了解决我们的问题,我们只是撕掉了整个函数。 我们不再支持 IE9,而且我们知道我们所有支持的浏览器都能正确处理媒体查询。

相关(但不完全重复)问题:

于 2018-03-07T21:24:55.333 回答
3

如果其他人有与跨域资源共享 (CORS) 政策相关的问题,请在此处讨论:https ://github.com/Modernizr/Modernizr/issues/2296

您必须使用本地主机进行测试: https ://developer.mozilla.org/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server

这是“尝试/捕获”方法的解决方法:

try {
  var classes = stylesheets[s].rules || stylesheets[s].cssRules;
} catch (e) {
  console.warn("Can't read the css rules of: " + stylesheets[s].href, e);
  continue
}

有这个问题并且绞尽脑汁,这似乎有效......祝你好运!

于 2018-10-05T21:22:11.627 回答
0

对我来说,将css链接href从标题移动到正文标签结尾。

<link rel="stylesheet" href=".....">
</body>
于 2020-03-11T16:21:40.327 回答