#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()
.