11522 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous,

J'essaie tant bien que mal de faire du JavaScript non intrusif, et j'ai besoin de spécifier 2-3 propriétés CSS valables uniquement lorsque JavaScript est activé.

J'utilise donc par exemple:

		function FondNoir()
		{
	document.getElementById('mondiv').style.background='black';
		}
window.onload=FondNoir;


Malheureusement, l'effet n'apparaît pas immédiatement, ce qui provoque un clignotement désagréable, surtout sous IE.
Comment peut-on y remédier ?
Modifié par Noisequik (15 May 2008 - 08:23)
Salut,

Tu peux essayer d'utiliser une fonction onDomReady qui te permettra de lancer la fonction juste après le chargement du DOM et ainsi éviter ou du moins minimiser le clignotement


// based on work by Matthias Miller, Dean Edwards and John Resig
onDomReady = (function(){

  // create event function stack
  var load_events = [],load_timer,done,exec,old_onload,
  init = function () {
    done = true;    
    clearInterval(load_timer);// kill the timer
    while (exec = load_events.shift()){
      exec();
    }
  };

  return function(func){
    
    if (done) return func();// if the init function was already ran, just run 
    
    if (!load_events[0]) {
      if(document.readyState && window.ActiveXObject){
        if (!document.getElementById('ie_ready')){
          var src = (window.location.protocol == 'https:') ? '://0' : 'javascript:void(0)';
				  document.write('<script id="ie_ready" defer src="' + src + '"><\/script>');
				  document.getElementById('ie_ready').onreadystatechange = function(){
				    if (this.readyState == "complete"){
					    init();
					  }
				  };
			  }
      }else if (document.readyState && /WebKit/i.test(navigator.userAgent)){ // for Safari      
        load_timer = setInterval(function() {
          if (/loaded|complete/.test(document.readyState))
            init(); // call the onload handler
          }, 30);          
      }else if(document.addEventListener){// for other browsers
        document.addEventListener("DOMContentLoaded", init, false);        
      }else{
        old_onload = window.onload;
        window.onload = function() {
          init();
          if (old_onload) old_onload();
        };
      }
    }
    load_events.push(func);
  }
})();


à utiliser ainsi :

onDomReady(function(){
   FondNoir()
})


Tu peux aussi essayer celle ci : http://snipplr.com/view/2337/ondomready/
la seule manière c'est d'ajouter une classe CSS avant même que tout contenu soit chargé.
matmat, ta méthode pourrait-être utile, mais ca ferait quand même un effet moche (sur une page de 70Ko en HTML ca se verrait assez bien sur une ligne en 128kbps)

la meilleure méthode la voici :
JS à mettre au tout début de ton fichier JS:

document.documentElement.className+=" hasJS"

on rajoute une classe CSS dur l'élément HTML de la page (pas sur le body, car il n'existe pas à ce moment là)

ensuite en CSS :

.maclasse {color:red; background:green} /* version sans JS */
.hasJS .maclasse {color:white; background:blue} /* version avec JS */


Je me sers énormément de cette méthode pour cacher des éléments seulement quand le JS est activé
Modifié par Gatsu35 (14 May 2008 - 19:08)
Gatsu35 a écrit :
la seule manière c'est d'ajouter une classe CSS avant même que tout contenu soit chargé.
matmat, ta méthode pourrait-être utile, mais ca ferait quand même un effet moche (sur une page de 70Ko en HTML ca se verrait assez bien sur une ligne en 128kbps)


Au vu de mes différents essais avec onDomReady, il arrive même que le js se charge avant le css, surtout si il est placé dans le header avant celui ci. Mais bon c'est sur que d'inclure les scripts directement dans le html marche très bien aussi, je l'ai fais pendant longtemps avant de m'apercevoir que cela peut poser parfois des problèmes de plantages et des complications de mise a jour.

A long terme je crois quand même que le onDomReady est la solution la plus sûre et la plus propre.
Modifié par matmat (14 May 2008 - 21:27)
matmat a écrit :


Au vu de mes différents essais avec onDomReady, il arrive même que le js se charge avant le css, surtout si il est placé dans le header avant celui ci. Mais bon c'est sur que d'inclure les scripts directement dans le html marche très bien aussi, je l'ai fais pendant longtemps avant de m'apercevoir que cela peut poser parfois des problèmes de plantages et des complications de mise a jour.

A long terme je crois quand même que le onDomReady est la solution la plus sûre et la plus propre.

Je n'ai jamais dit que j'incluais la ligne de JS dans le HTML
la ligne de JS que j'ai filé tu la fous dans ton fichier JS principal de ton site.
mais ça doit etre un fichier qui est appelé dans le header.

Ensuite, je vais te contredire, mais sur les sites qu'on monte actuellement, si on utilisait du domready pour cacher des éléments d'une barre de navigation par exemple, cela ne fait vraiment pas joli à voir, puisque tu vois des trucs affichés qui une fois la page chargé disparaissent.
Des trucs comme ça, ça saute aux yeux du client, crois en mon expérience.
Pour moi le domready il est très bien pour initialiser des éléments, mais pas pour les cacher.
Pour ça il y a la CSS couplé à une classe parent qui n'est appliquée que si le JS est présent. C'est la seule méthode viable à l'heure actuelle.

Mais je répète, je n'ai jamais dit de coller cette ligne de JS dans la page HTML Smiley lol
Je ne connaissais pas cette technique, est ce que tu aurais des liens vers des discutions ou des pages qui en parle?

edit : j'en ai trouvé un mais qui ne compare pas avec domReady : http://wojciechbednarski.com/web-accessibility/the-best-way-to-hide-content-by-javascript

et ici un autre qui parle de domReady (voir les commentaires) ainsi que de la même technique mais pour l'élément body qui semble moins propre que la tienne. http://arapehlivanian.com/2007/02/14/understanding-and-solving-the-javascriptcss-entanglement-phenomenon/
Modifié par matmat (15 May 2008 - 01:21)
Et pourquoi ne pas tout simplement charger une feuille de style spéciale lorsque javascript est activé grâce à un :


<script language="javascript" type="text/javascript">
/* <![CDATA[ */ 
document.write('<link rel="stylesheet" type="text/css" href="javascript.css" media="screen" />'); 
/* ]]> */
</script>


( A placer dans le <head> bien sur, après les feuilles de styles normales, de façon à overrider les définitions précédentes ).
Ainsi pas de FoC, et on garde les styles pour javascript centralisés dans un seul fichier.
Modifié par Tymlis (15 May 2008 - 03:31)
Tymlis a écrit :
Et pourquoi ne pas tout simplement charger une feuille de style spéciale lorsque javascript est activé grâce à un :


<script language="javascript" type="text/javascript">
/* <![CDATA[ */ 
document.write('<link rel="stylesheet" type="text/css" href="javascript.css" media="screen" />'); 
/* ]]> */
</script>


( A placer dans le <head> bien sur, après les feuilles de styles normales, de façon à overrider les définitions précédentes ).
Ainsi pas de FoC, et on garde les styles pour javascript centralisés dans un seul fichier.

Ben là tu te fais chier avec un truc en plus qui entraine des emmerdes en plus :
- 1 fichier en plus
- 1 hit sur le serveur dont on pourrait se passer
- devoir maintenir les styles d'un même élément dans plusieurs feuilles de styles, alors que dans ce cas précis (une ligne change) ce n'est vraiment pas nécessaire.
- devoir se trimballer une ligne de JS lourde, qui bien sur pourrait être transposer dans un fichier JS, je te l'accorde.

Ce que je viens de citer est aussi valable pour une feuille de style alternative IE pour les gens qui n'aimes pas les hacks. Les hacks c'est bon, mangez en, mais intelligemment Smiley lol
Vous verrez quand vous atteindrez des feuilles de styles de l'ampleurs de ce qu'on manie par chez moi Smiley lol , et pourtant ce sont des CSS optimisés à la source.

Pour revenir à la discussion avec Matmat, la seule méthode que les gens connaissent c'est mettre une classe sur le body. J'ai vu que d'autres justement utilisaient cette méthode lors d'une présentation au Wasp Café n°2 par des gars de chez Yahoo. Et le résultat a été que tu était obligé de te coltiner une ligne à mettre juste après ton body.
Avant j'utilisais un JS avec un setTimeout qui attendait que le body apparaisse pour coller la classe

function hasJSOnBody() {
   if (document.body) 
        document.body.className+=" hasJS";
   else setTimeout(hasJSOnBody, 10);
}
hasJSOnBody();

Mais cette chose avait des effets un peu pervers au niveau comportemental sur certains sites. Et un ptit génie qui est passé par chez nous à trouvé cette solution smart de le coller sur le document.documentElement, qui correspond à l'élément HTML

Autre petite précision: Cette méthode évite aussi de devoir parcourir le dom à la recherche d'élément à cacher. Ca fait un traitement en moins, et quand on a des paquets de trucs applicatifs sur une page, c'est déjà ça de pris.
Il n'y a rien de plus rapide que le moteur CSS pour afficher / cacher des éléments via une classe parent
Modifié par Gatsu35 (15 May 2008 - 05:56)
Voilà j'ai procédé à des tests, et la méthode de Gatsu35 fonctionne à merveille !

On ne voit plus du tout au démarrage les propriétés qui doivent être remplacées par la class hasJS Smiley biggrin

avec la solution de matmat, je n'ai pas vu de différence par rapport à mon code initial, malheureusement...

Je vais pouvoir m'amuser un peu, et améliorer les sites déjà existant; je suppose que cela va m'être utile pour corriger le même problème lorsque j'utilise des scripts comme script.aculo.us qui jouent sur l'opacité.