2013-07-19 3 views
8

У меня есть код (это на самом деле не моя, а библиотека SlickGrid), которая создает элемент <style>, вставляет его в DOM, а затем сразу же пытается найти новую таблицу стилей в коллекции document.styleSheets.Webkit - динамически созданная таблица стилей - когда она действительно загружается?

В WebKit это иногда терпит неудачу. На самом деле я не знаю, каковы обстоятельства, но это ничего не воспроизводится последовательно. Я полагал, что я мог бы работать вокруг него путем изменения кода, поэтому проверка объекта StyleSheet не произойдет, пока load событие на элемент стиля, например, так:

$style = $("<style type='text/css' rel='stylesheet' />").appendTo($("head")); 
    var rules = ...;// code to create the text of the rules here 
    if ($style[0].styleSheet) { // IE 
    $style[0].styleSheet.cssText = rules.join(" "); 
    } else { 
    $style[0].appendChild(document.createTextNode(rules.join(" "))); 
    } 
    $style.bind('load', function() { 
      functionThatExpectsTheStylesheet(); 
    }); 

и functionThatExpectsTheStylesheet пытается найти реальный объект таблицы стилей например:

var sheets = document.styleSheets; 
    for (var i = 0; i < sheets.length; i++) { 
     if ((sheets[i].ownerNode || sheets[i].owningElement) == $style[0]) { 
     stylesheet = sheets[i]; 
     break; 
     } 
    } 

, но иногда даже в этот момент объект stylesheet не найден.

Так, мой вопрос заключается в следующем:

  1. ли load события на самом деле не гарантирует, что объект STYLESHEET будет доступен? Это ошибка?
  2. Если нет, есть ли другое условие, которое я могу использовать или просто мне нужно сделать, используя таймауты?
  3. Или есть некоторые проблемы с тем, как я привязываю событие загрузки, и это моя проблема?
+1

Я думаю, что делает Fiddle бы полезным – Brewal

+1

Может быть дубликатом http://stackoverflow.com/questions/8060429/when-is-a-stylesheet-added-to-document-stylesheets –

+0

@Brewal Я могу попробовать это, но это случается менее чем в 10% случаев в моих реальных тестах, поэтому я не знаю, насколько это было бы полезно. – Dan

ответ

6

Динамическая загрузка CSS-таблиц стилей по-прежнему является областью, заполненной чертами браузера, к сожалению. В Webkit, <style> и <link> элементы будут загружены как fire load and error events при загрузке таблиц стилей. Однако само событие load означает только то, что загружен ресурс таблицы стилей, не обязательно, что он был добавлен в document.styleSheets.

require-css RequireJS погрузчик имеет дело с этой проблемой путем разветвления его загрузка механизма, основанный на UserAgent нюхает (это почти невозможно, чтобы показать, обнаружить, будет ли или не <link> тег правильно уволить его load события). Специально для Webkit, обнаружение курортов в использовании setTimeout найти, когда объект StyleSheet был присоединен к document.styleSheets

var webkitLoadCheck = function(link, callback) { 
    setTimeout(function() { 
    for (var i = 0; i < document.styleSheets.length; i++) { 
     var sheet = document.styleSheets[i]; 
     if (sheet.href == link.href) 
     return callback(); 
    } 
    webkitLoadCheck(link, callback); 
    }, 10); 
} 

Так что пока load событие будет срабатывать на Webkit, он ненадежен для целей возможности доступа к соответствующий StyleSheet экземпляр. В настоящий момент единственным движком, поддерживающим таблицы стилей load, является Firefox 18+.

Раскрытие: Я вкладчик требовать, CSS

Ссылки:

0
  1. Я думаю, что событие загрузки может быть запущен раньше, чем таблицы стилей CSS. Проблема может произойти, возможно, в 1 из 10 раз, но ее по-прежнему не самая лучшая практика и самый чистый способ.

  2. setTimeout, безусловно, хороший подход, так как можно гарантировать, что ваш скрипт загружает сначала css. Однако, поскольку только тег таблицы стилей, значит, создается ссылка на него, сначала нужно загрузить css, поэтому любой подход этих двух, которые вы используете, никогда не гарантирует 100%, что ваш css загружен до события загрузки пожары.

Чтобы быть 100% уверены, что все работает в правильном порядке будет, чтобы сделать синхронное FileRead через AJAX или асинхронный AJAX вызова с помощью функции хелперов, которая проверяет, если CSS готов (таким образом, вы не замерзнуть браузер, но все же есть возможность проверить, загружен ли файл или нет). Другой способ - просто связать руководство по стилям: сначала задайте таблицы стилей, а затем введите код в заголовке вашего HTML-файла.

Я не смотрю так глубоко в события нагрузки, но это может быть, что событие DOMContentLoaded только стреляя CSS загружается (плохое исследование на этом)

Посмотрите здесь для похожа вопроса: jQuery event that triggers after CSS is loaded?

+0

Я не совсем понимаю, что может быть более синхронным, чем создание элемента 'style' и добавление его к самому DOM? Также я забыл упомянуть - код, о котором я говорю, обычно не запускается при загрузке страницы, но позже. – Dan

+0

И просто чтобы быть ясным (может быть, в моем вопросе это было недостаточно) - я не загружаю внешнюю таблицу стилей. Я создаю внутреннюю с текстом фактических правил, сгенерированным с помощью JS-кода. – Dan

0

Я не утверждаю, что у меня есть решение, ни объяснение времени загрузки Webkit, но у меня недавно была аналогичная проблема, но с JS: мне нужно было быть абсолютно уверенным в том, что структура jQuery была загружена, прежде чем включать другие библиотеки мой собственный, который зависел от jQuery.

Я заметил, что событие jQuery не было выпущено, когда я ожидал его.

Для чего это стоит, вот как я решил мою проблему:

var addedHead = window.document.createElement('link'); 

addedHead.async = true; 
addedHead.onload = addedHead.onreadystatechange = function() { 

    if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') 
    { 
     callback(); 
     addedHead.onload = addedHead.onreadystatechange = null; 
    } 
}; 
//And then append it to the head tag 

Вы могли бы дать ему попробовать!

+0

Опять же, это не элемент 'link', это элемент' style' с встроенными правилами. Внешних ресурсов нет. – Dan

0

Приходилось также использовать определение правила стиля, чтобы проверить, была ли загружена таблица стилей.

// Load CSS dynamically. There's no way to determine when stylesheet has been loaded 
// so we usingn hack - define `#my-css-loaded {position: absolute;}` rule in stylesheet 
// and the `callback` will be called when it's loaded. 
var loadCss = function(url, cssFileId, callback){ 
    // CSS in IE can be added only with `createStyleSheet`. 
    if(document.createStyleSheet) document.createStyleSheet(url) 
    else $('<link rel="stylesheet" type="text/css" href="' + url + '" />').appendTo('head') 

    // There's no API to notify when styles will be loaded, using hack to 
    // determine if it's loaded or not. 
    var $testEl = $('<div id="' + cssFileId + '" style="display: none;"></div>').appendTo('body')  
    var checkIfStyleHasBeenLoaded = function(){ 
    if($testEl.css('position') == 'absolute'){ 
     $testEl.remove() 
     callback() 
    }else setTimeout(checkIfStyleHasBeenLoaded, 10) 
    } 
    setTimeout(checkIfStyleHasBeenLoaded, 0) 
} 
Смежные вопросы