3 votes

Création du nœud de style, ajout de innerHTML, ajout au DOM et maux de tête d'IE

J'ai une question en deux parties.

D'abord, le scénario :

En raison de certains problèmes bizarres que nous avons rencontrés en ce qui concerne la prise en charge de NOSCRIPT par les navigateurs mobiles, je suis chargé de trouver une solution alternative pour "détecter" JS. La logique de la solution consiste à avoir deux DIVs sur la page. L'un est une erreur indiquant que vous n'avez pas de JS et il est affiché par défaut. Si l'un d'eux contient du JS, nous voulons alors ajouter un nouveau bloc STYLE au HEAD qui remplace le CSS précédent et cache l'erreur pour afficher le contenu.

L'échantillon HTML :

<div id="div1">div 1 (should be shown if JS enabled)</div>
<div id="div2">div 2 (should be hidden if JS enabled)</div>

C'est le JS avec lequel j'ai commencé :

  var styleNode = document.createElement('style');
  styleNode.setAttribute("type", "text/css");
  styleNode.innerHTML = "#div1 {display: block;} #div2 {display: none;}";
  headTag.appendChild(styleNode);

Mais, j'avais des problèmes. En cherchant sur Google, j'ai trouvé cette description d'un problème de sécurité que peut rencontrer IE si vous essayez d'insérer innerHTML dans un élément créé avant de le placer dans le DOM :

http://karma.nucleuscms.org/item/101

Donc, j'ai modifié le script comme tel :

  var styleNode = document.createElement('style');
  styleNode.setAttribute("type", "text/css");
  var headTag = document.getElementsByTagName("head")[0];
  headTag.appendChild(styleNode);
  var aStyleTags = headTag.getElementsByTagName("style");
  var justAddedStyleTag = aStyleTags[aStyleTags.length-1];
  justAddedStyleTag.innerHTML = "#div1 {display: block;} #div2 {display: none;}";

question 1 : s'agit-il d'une solution de contournement valable pour le problème d'IE ? Existe-t-il une solution plus efficace ?

question 2 : même avec l'ajustement, le script ne fonctionne toujours pas dans IE. Il fonctionne bien dans Firefox, mais dans IE 7, j'obtiens une "erreur d'exécution inconnue".

J'ai un exemple de ce code sur JSBIN :

http://jsbin.com/ucesi4/4

Quelqu'un sait ce qui se passe avec IE ?

UPDATE :

Je suis tombé sur ce lien via google. Notez le dernier commentaire :

http://msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx

Cela dit, vous devriez vraiment mettre tous règles de style dans le HEAD pour une stricte conformité avec le XHTML. Faire cela peut également être un peu délicate car vous ne pouvez pas utiliser innerHTML pour injecter dans l'élément HEAD ou STYLE directement. (Ces deux balises sont en LECTURE SEULE).

Eep ! Vrai ? Est-ce que FireFox est juste trop indulgent ? Ou est-ce juste une bizarrerie d'IE ?

UPDATE 2 :

Un peu plus d'informations sur ce que nous essayons de résoudre ici. Nous avons affaire à des appareils mobiles et certains de ces appareils archaïques a) ne supportent pas NOSCRIPT et b) ont des moteurs JS lents.

Comme ils ne prennent pas en charge le NOSCRIPT, nous affichons par défaut une erreur, puis nous la masquons via JS s'ils en ont un, et nous leur présentons le contenu approprié. En raison de la lenteur des moteurs JS sur ces sites, les gens voient le "scintillement" de l'affichage et du masquage des DIV. C'est la solution proposée pour gérer cela, car elle charge le CSS avant même que les DIVs ne soient rendus.

Puisqu'il semble être invalide, la solution sera que sur ces anciens appareils, nous utiliserons cette méthode (puisqu'elle semble fonctionner, même si ce n'est pas dans IE) et ensuite tous les autres navigateurs corrects feront comme suggéré... nous mettrons juste à jour la propriété CSS DISPLAY via JS en ligne après que chaque DIV soit chargé dans le DOM.

Cela dit, je suis toujours curieux de savoir si ce problème est un bug d'IE, ou si IE adhère réellement aux normes appropriées en faisant de STYLE un élément en lecture seule.

6voto

arnaud576875 Points 35281

Dans IE, vous pouvez utiliser style.styleSheet.cssText :

var style = document.createElement('style');
style.type = 'text/css';

if (style.styleSheet) { // IE
    style.styleSheet.cssText = css;
} else {
    style.appendChild(document.createTextNode(css));
}

document.getElementsByTagName('head')[0].appendChild(style);

Essayez ici : http://jsfiddle.net/QqF77/

Voir la réponse à cette question : Comment créer une balise <style> avec Javascript

1voto

Martin Jespersen Points 13702

N'utilisez pas innerHTML utiliser document.createTextNode() et votre vie deviendra infiniment meilleure ;)

var styleNode = document.createElement('style');
styleNode.setAttribute("type", "text/css");
var textNode = document.createTextNode("#div1 {display: block;} #div2 {display: none;}");
styleNode.appendChild(textNode);
headTag.appendChild(styleNode);

EDITAR:

Puisque cette solution ne semble pas fonctionner pour vous, je l'abandonnerais. Préférez une solution où les styles sont déjà définis et où vous n'avez qu'à désactiver/activer les styles via javascript si disponible.

Vous pouvez le faire de cette façon :

<head>
<style>
.jsenabled #div2, #div1 { display: none;}
.jsenabled #div1, #div2 { display: block;}
</style>
<script>
//i know you don't use jQuery, but the solution should still be valid as a concept
//bind to DOM-ready, then set the class jsenabled on the body tag
$(function() {
 $(document.body).addClass('jsenabled');
});
</script>
</head>
<body>
<div id="div1">div 1 (should be shown if JS enabled)</div>
<div id="div2">div 2 (should be hidden if JS enabled)</div>
</body>

EDIT 2 :

Si cela doit être fait avant que le DOM soit prêt, vous pourriez faire quelque chose d'assez laid comme ceci :

<head>
<style>
#div2, .show { display: block;}
#div1, .hide { display: none;}
</style>
</head>
<body>
<div class="hide">
<script>document.write('</div><div id="div1">');</script>
   div 1 (should be shown if JS enabled)
</div>
<script>document.write('<div class="hide">');</script>
<div id="div2">div 2 (should be hidden if JS enabled)</div>
<script>document.write('</div>');</script>
</body>

Ou pour garder les choses simples, vous pouvez simplement faire

<head>
<script>document.write('<style>#div1 {display: block;} #div2 {display: none;}</style>');
</head>
<body>
<div id="div1">div 1 (should be shown if JS enabled)</div>
<div id="div2">div 2 (should be hidden if JS enabled)</div>
</body>

0voto

Chuck Kollars Points 884

La meilleure pratique consiste à mettre tous les <link pour CSS dans le <head>, et la plupart des <script à la toute fin du <body> (sauf les courts fragments de <script qui doivent s'exécuter au plus vite doivent aller dans le <head>). La norme et les navigateurs vous permettent de faire des choses stupides, mais ce n'est pas parce que c'est acceptable que c'est une bonne idée.

Plutôt que de passer par tout le charabia de la création d'un nœud Style et de la manipulation du DOM (qui ne font que fournir plus d'opportunités pour que quelque chose se passe mal), je recommande un nœud beaucoup une solution plus simple. Coder en dur autant que possible dans votre document (et feuille de style ?) une fois à l'avance (plutôt que de créer des choses à la volée à chaque fois). Voici un exemple approximatif :

<body ...
...
<div id="warning" style="display: block;">
JS is required for this site, but isn't available ...
</div>
<div id="message" style="display: none;">
JS is available
</div>
...

<script ...
var warningEl = document.getElementById('warning');
warningEl.style.display = 'none';
var messageEl = document.getElementById('message');
messageEl.style.display = 'block';
</script ...

Cela devrait fonctionner raisonnablement bien la plupart du temps (cela fonctionnera certainement dans plus de navigateurs que ce que vous avez essayé de faire initialement). Cependant , tout tenter de modifier le DOM dans tout avant que la page ne soit initialement affichée à l'utilisateur. pas garantie de fonctionner (en d'autres termes, ni votre façon ni l'exemple ci-dessus sera toujours fonctionnent dans tous les cas). Plus vous exécutez votre Javascript tôt, plus les opérations DOM (y compris getElementById) risquent d'échouer. Et plus vous exécutez votre Javascript tard, plus l'utilisateur risque de remarquer un "scintillement" perceptible de son écran. Vous devez donc faire un choix entre une compatibilité étendue et un scintillement perceptible.

Vous pouvez attendre que le DOM soit garanti comme étant entièrement prêt avant d'exécuter votre Javascript ("ready" dans jQuery, ou addEventListener 'domcontextloaded', ou même addEventListener 'load'). Le fonctionnement correct est garanti dans tous les cas. Mais il scintillera (peut-être assez mal) dans de nombreux cas.

Le seul moyen que je connaisse (mais j'espère que quelqu'un d'autre en sait plus :-) pour éviter totalement la possibilité de scintillement est de mettre dans l'en-tête un fragment de Javascript qui change window.location mais ne fait rien d'autre. (Pas de références au DOM, qui sont généralement rendues évidentes par le mot "document" quelque part dans le code). L'effet net, si le JS est disponible, sera un rechargement immédiat d'une page différente avant que l'utilisateur ne voie quoi que ce soit. La page initiale peut contenir votre avertissement, et la nouvelle page, le vrai contenu, sans avertissement.

Même cette méthode présente des inconvénients : Tout d'abord, le double téléchargement prend de la bande passante supplémentaire et retarde un peu la visibilité de l'utilisateur. Cela n'a pas d'importance sur les ordinateurs de bureau classiques. Mais sur les ordinateurs de poche, cela peut ne pas être acceptable. Et deuxièmement, cela aura des répercussions sur le référencement. La deuxième page - qui est censée être invisible et accessible uniquement à partir de la première page - peut apparaître indépendamment dans les webdex, de sorte que les utilisateurs peuvent facilement y accéder directement (vous pouvez peut-être "corriger" ce problème en utilisant intelligemment "canonical" et/ou "meta...robots"). Et le SERP de la page initiale peut chuter précipitamment lorsque son seul contenu est le message d'avertissement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X