Uncaught DOMException: не удалось прочитать свойство "rules" из "CSSStyleSheet"

В редакторе App Lab Code.org мы недавно начали видеть эту ошибку в 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, и, похоже, мы не можем воспроизвести проблему в окне инкогнито.

Какова основная причина этой ошибки?

2 ответа

Решение

Это была хорошая история и новая "проблема" для веб-разработчиков, поэтому мне просто хотелось поделиться:

В Chrome 64.0.3282.0 (выпущен в январе 2018 года, полный список изменений) внесены изменения в правила безопасности для таблиц стилей. Меня раздражает, что я не могу найти это изменение в любом журнале изменений, менее подробном, чем полный список коммитов.

Коммит a4ebe08 в Chromium описан:

Обновить поведение CSSStyleSheet, чтобы оно соответствовало спецификации источника безопасности

Спецификация здесь: https://www.w3.org/TR/cssom-1/

Обновлено: следующие методы теперь выдают ошибку SecurityError, если таблица стилей недоступна:

  • cssRules () / rules ()
  • insertRule ()
  • deleteRule ()

Этот коммит исправляет ошибку Security: Несогласованная реализация CORS относительно CSS и элемента link. Связанная спецификация W3C подробно описывает, где использование объектной модели CSS требует доступа того же источника.

Все это говорит о том, почему эта проблема обнаруживается в App Lab? Мы не должны испытывать никаких проблем с CORS, потому что мы загружаем таблицы стилей только из нашего собственного источника:

Вкладка сети Chrome, отображающая все CSS-запросы, запрошенные на соответствующей странице

В итоге намекнули, что мы не можем воспроизвести эту проблему на закрытой вкладке. Мы начали смотреть на расширения Chrome и поняли, что у некоторых затронутых пользователей было включено расширение Loom Video Recorder, которое, похоже, внедряет свой собственный CSS в страницу. Поскольку наша (наивная) функция выполняла итерацию по всем загруженным таблицам стилей, она пыталась получить доступ к этой таблице стилей, введенной расширением, и, таким образом, вызвала ошибку CORS.

Тем не менее, есть еще некоторые открытые вопросы и дебаты вокруг этого изменения в Chrome:

  • В этом комментарии к исходной ошибке безопасности сообщается, что единственный способ определить, что таблица стилей недоступна из JavaScript, - это try/catch,
  • Ошибка Chromium, открытая 23 января ( document.styleSheets.cssRules является нулевой, даже с Access-Control-Allow-Origin: *), предполагает, что может быть проблема реализации с новым правилом безопасности, которое нарушает определенные обходные пути.
  • Реализуемая спецификация кажется довольно стабильной, но она все еще имеет статус "Рабочий проект", так что кто знает, где она появится и что будут реализовывать другие браузеры.

Чтобы решить нашу проблему, мы просто оторвали всю функцию. Мы больше не поддерживаем IE9, и мы знаем, что все наши поддерживаемые браузеры правильно обрабатывают медиазапросы.

Смежные (но не совсем повторяющиеся) вопросы:

Если у кого-то еще есть эта проблема, связанная с политикой общего доступа к ресурсам (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
}

Была эта проблема и ломала мне голову, и это, казалось, работало... Удачи!

Для меня работает, чтобы переместить ссылку css href из заголовка в конец тега тела.

<link rel="stylesheet" href=".....">
</body>
Другие вопросы по тегам