Когда добавляется таблица стилей в document.styleSheets

#javascript #jquery #css #google-chrome #stylesheet

#javascript #jquery #css #google-chrome #таблица стилей

Вопрос:

Я пытаюсь динамически добавить правило таблицы стилей css, используя javascript, что-то вроде здесь примера 2.

Большую часть времени это работает, но, похоже, существует условие гонки, из-за которого иногда происходит сбой в (по крайней мере) Chrome (15.0.874 и 17.0.933). Это случается нечасто, когда кэш пуст (или был очищен).

Вот до чего мне удалось сузить круг поиска. Сначала я загружаю внешнюю таблицу стилей, добавляя ее в <head> , а затем создаю новую таблицу стилей (куда я бы добавил правила). Затем я печатаю длину document.styleSheets (немедленно и через 1 секунду).

 $(function() {
    // it doesn't happen if this line is missing.
    $("head").append('<link rel="stylesheet" type="text/css"' 
                     'href="/css/normalize.css" />');

    var stylesheet = document.createElement("style");
    stylesheet.setAttribute("type", "text/css");
    document.getElementsByTagName('head')[0].appendChild(stylesheet);

    var b = $('body');
    b.append(document.styleSheets.length).append('<br/>');
    setTimeout(function() {
        b.append(document.styleSheets.length).append('<br/>');
    }, 1000);
});
  

(поиграйте с этим вhttp://jsfiddle.net/amirshim/gAYzY/13 /)

Когда кэш очищен, он иногда печатает 2 тогда 4 (jsfiddle добавляет свои собственные 2 css-файла), что означает, что он не добавляет ни одну из таблиц стилей в document.styleSheets немедленно… но, вероятно, ожидает загрузки внешнего файла.

Ожидается ли это?

Если да, то не поврежден ли пример 2 в MDN (и многие другие)? Начиная со строки 27:

 var s = document.styleSheets[document.styleSheets.length - 1];
  

может вычисляться с document.styleSheets.length == 0

Обратите внимание, что этого не происходит, если я сначала не загружаю внешний файл CSS.

Комментарии:

1. Я хотел бы спросить вас, каков ваш желаемый конечный результат. При каких обстоятельствах вы хотели бы «внедрить» правило в файл css, а не просто записать его внутри файла css в первую очередь?

2. Я тоже добавляю таблицу стилей динамически … но только после $ (document). сработала функция ready…

3. @Kees: Приведенный мной код выполняет все в $(document).ready . Вот что $(function() {...}); делает.

4. @Sotkra У нас есть рабочий процесс разработчика (не обязательно обоснованный), в котором иногда проще просто изменить JS-файл, над которым вы работаете, чем изменять JS и (общий) CSS-файл, поэтому я предоставляю функцию addRule(...) , которая позволяет разработчикам добавлять правила «на лету» для страницы, которую генерирует js-файл. Обычно они объединяются в файл CSS позже. Другая причина этого — изменение стиля «на лету»; взгляните на jqueryui.com/themeroller

Ответ №1:

Если JavaScript находится на странице под CSS (что почти всегда так и есть), анализатор HTML должен дождаться выполнения JS, пока JS и CSS не будут полностью загружены и проанализированы из-за того факта, что JS может запросить информацию о стиле (Chrome делает это только тогда, когда скрипт действительно это делает). Это эффективно блокирует загрузку внешнего CSS почти во всех случаях. Когда вы вставляете их позже с помощью JavaScript или на странице нет JS (или JS загружается неблокирующим образом), CSS загружается асинхронно, что означает, что они загружаются и анализируются без блокирования синтаксического анализа DOM. Поэтому количество documents.stylesheets обновляется только после того, как лист находится внутри DOM, и это происходит только после его полной загрузки и анализа.

В этой ситуации могут быть некоторые временные различия. Учитывая, что большинство браузеров имеют ограниченное количество каналов, через которые они загружают данные (у некоторых их всего два, как в IE6, у большинства их 6, а у некоторых даже 12, как в IE9), загрузка таблицы стилей добавляется в конец очереди для загрузки. Браузер все еще загружает вещи, потому что вы вызываете свою функцию в DOMReady. Что приводит к тому, что таблица стилей не загружается полностью и анализируется секундой позже, поэтому не влияет на document.stylesheets.длина.

И все примеры таблиц стилей, с которыми я сталкивался в Интернете, предполагают, что dom полностью проанализирован и загружен. Таблицы стилей OffDOM даже не позволяют вставлять или проверять правила из-за того, что у них могут быть правила @import, и они должны загружаться извне, поэтому для браузеров довольно сложно определить, когда безопасно взаимодействовать с листом, если они не полностью загружены и не проанализированы. Таблицы стилей OffDOM предоставляют пустое свойство sheet, но не позволят вам взаимодействовать с ним, пока лист не будет добавлен в DOM.

Я всегда считал, что лучше вставлять таблицу стилей динамически и выполнять все изменения на этом листе, оставляя document.stylesheets в покое. Это имеет большое преимущество в том, что при переопределении стилей с той же спецификацией у вас не возникнет проблем из-за вставки на неправильном листе. Поскольку document.stylesheets является активным списком узлов, document.stylesheets[ 2 ] может указывать на другой лист при каждом вызове функции (если не хранится в переменной). Поэтому я склонен использовать динамически вставляемый лист и работать только с ним.

Ответ №2:

Это должно помочь: ‘Когда таблица стилей действительно загружена

Что касается «Примера 2». Это приведет к сбою, если при вызове addStylesheetRules() будет загружена таблица стилей, конечно, это в Chrome.

Комментарии:

1. Итак, пример 2 не всегда работает. т.Е. если я (или другая библиотека js) просто добавил внешнюю таблицу стилей перед вызовом addStylesheetRules() .