Pages :
Bonjour à tous,

je suis nouveau sur le forum, même si je le suis activement depuis plusieurs années maintenant Smiley smile

Je suis développeur frontend et pourtant, une question me turlupine : Le poid des images.

Afin d'optimiser le poid d'une page, est il préférable d'utiliser css ou la balise img ?

Merci pour vos lumières.

Edit : ce post est en train de prendre une nouvelle tournure puisque mon animation connait des pertes de performances et je pense que ce n'est pas spécifiquement lié au poid des images en réalité..

Voici le lien de démo : http://desirelabs.fr/desirelabs

et le code source :

/* Script de génération d'images, animation, suppression */

var i = 0;
var screenWidth = parseInt($('body').innerWidth());


function generate(){

	do{ var haut = Math.floor(Math.random()*1000) } while(haut <= 5 || haut >= 75);
	do{ var largeur = Math.floor(Math.random()*1000) } while(largeur <= 50 || largeur >= 120);
	var frequence = 3000*Math.floor(Math.random()*10);
	var hauteur = (largeur/1.923);
	var opacite = 1;

	if(i <= 5){
		var speed = 700;
		do{ var gauche = Math.floor(Math.random()*1000) } while(gauche <= 5 || gauche >= screenWidth);
		
	}
	else{
		var speed = 1;
		var gauche = -75;
	}

	document.getElementById('space').innerHTML += '<div class="nuage nuage_'+i+'"></div>';
		
	$('#space .nuage_'+i).animate({opacity : opacite},speed);
	$('#space .nuage_'+i).css("top", haut);	
	$('#space .nuage_'+i).css("left", gauche);
	$('#space .nuage_'+i).css("width", largeur);
	$('#space .nuage_'+i).css("height", hauteur);

	i++;
	setTimeout("generate()",frequence);
}


function del(){
	$('#space .nuage').each(function(){
		if($(this).css("left").substr(0,4) >= screenWidth){
			$(this).remove();
		}
	});
	setTimeout("del()",1000);
}


function move(){
	$('#space .nuage').each(function(){
		if($(this).css("width").length == 5){
			var coef = parseInt($(this).css("width").substr(0,3));
		}
		else{
			var coef = parseInt($(this).css("width").substr(0,2));
		}
		var index = Math.floor(1/coef*1000);
		var speed = coef*1500;
		$(this).css("z-index", speed);
		$(this).innerHTML = speed;
		$(this).animate({left : 2000}, speed, "linear");
	})
	setTimeout("move()",10);
}



$(document).ready(function(){

	del();
	generate();
	move();

});

Modifié par neovea (29 Mar 2013 - 13:18)
Non en fait j'expérimente une animation dans laquelle j'ai un png qui est généré en plusieurs exemplaires et qui tourne en boucle. Au bas mot un total de 20~30 occurrences sont générées avec un poids d'un peu moins de 3ko. Sachant qu'en plus j'ai le poids du js, et que la page ne possède pas encore le reste du contenu, je crains le pire.
Modifié par neovea (28 Mar 2013 - 12:58)
Modérateur
Bonjour,

Est-ce que le png est la même image, c'est-à-dire le même fichier portant le même nom, qui est affichée plusieurs fois?

Il faut tenir compte de la cache du navigateur et il existe des outils pour mesurer le poids d'une page (ex: Web Developer Toolbar pour Firefox).
Oui en effet, c'est la même image qui se répète. J'ai laissé tourner l'animation tout l'après midi, et là je constate de forts ralentissements de mon navigateur. Je me demande comment ça se fait, si j'utilise une seule et même image, il ne devrait la stocker qu'une seule fois dans le cache si je ne me trompe pas, non ?

Je pense qu'il va falloir que je cherche de quelle façon optimiser mon script et le cache du navigateur pour éviter ce genre de problèmes. Mais comme je ne suis pas expert JS, je me documente.

Merci pour le lien Olivier. Dommage que ça ne fonctionne pas avec les url locales. Mais c'est toujours bon à avoir sous la main ce type d'outil Smiley smile

Si vous avez d'autres infos pertinentes je suis tout oui Smiley smile
Modifié par neovea (28 Mar 2013 - 18:56)
neovea a écrit :
Si vous avez d'autres infos pertinentes je suis tout oui Smiley smile

Et bien tant que nous y sommes : afin de réduire le poids des images sans aucune perte de qualité, utilisez des logiciel tels que imageOptim (sous Mac, il y a des équivalents PC). Vous pouvez obtenir des gains de 5% à 70% du poids d'origine (suppression des métadonnées de l'image). Il existe un outil en ligne : Smush.it (Wordpress a même un plugin permettant de le faire de manière transparente à l'utilisateur).

Avec perte de qualité : sachez que, sur le web, enregistrer une image à 80% de sa qualité (et même jusqu'à 60%) n'a quasiment aucune incidence visuelle... à tester. Ne pas oublier de les passer en 72dpi.
Modifié par Olivier C (29 Mar 2013 - 00:40)
Sois béni Olivier ! (même si pour le coup c'est toi qui t'y colles Smiley cligne ) Avec ton lien j'ai économisé près de 30ko.
Bon je bosse toujours sur mon script, mais en fait je me rends compte qu'outre le poids des images, c'est mon script qui à force de tourner en boucle, finit par consommer des ressources.

Comme je l'ai déjà dit, je ne suis pas expert JS et je cherche d'où peut venir cette fuite de performance.

Je vous poste mon code :


	var i = 0;
	var screenWidth = parseInt($('body').innerWidth());


function generate(){

	do{ var haut = Math.floor(Math.random()*1000) } while(haut <= 5 || haut >= 75);
	do{ var largeur = Math.floor(Math.random()*1000) } while(largeur <= 50 || largeur >= 120);
	var frequence = 3000*Math.floor(Math.random()*10);
	var hauteur = (largeur/1.923);
	var opacite = 1;

	if(i <= 7){
		var speed = 700;
		do{ var gauche = Math.floor(Math.random()*1000) } while(gauche <= 5 || gauche >= screenWidth);
		
	}
	else{
		var speed = 1;
		var gauche = -75;
	}

	document.getElementById('space').innerHTML += '<div class="nuage nuage_'+i+'"></div>';
		
	$('#space .nuage_'+i).animate({opacity : opacite},speed);
	$('#space .nuage_'+i).css("top", haut);	
	$('#space .nuage_'+i).css("left", gauche);
	$('#space .nuage_'+i).css("width", largeur);
	$('#space .nuage_'+i).css("height", hauteur);

	i++;
	setTimeout("generate()",frequence);
}


function del(){
	$('#space .nuage').each(function(){
		if($(this).css("left").substr(0,4) >= screenWidth){
			$(this).remove();
		}
	});
	setTimeout("del()",1000);
}


function move(){
	$('#space .nuage').each(function(){
		if($(this).css("width").length == 5){
			var coef = $(this).css("width").substr(0,3);
		}
		else{
			var coef = $(this).css("width").substr(0,2);
		}
		var index = Math.floor(1/coef*1000);
		var speed = coef*1500;
		$(this).animate({left : 2000},speed,'linear');
		$(this).css("z-index", index);
	})
	setTimeout("move()",10);
}



$(document).ready(function(){

	//setInterval(function(){generate()}, 1000);
	del();
	generate();
	move();

});


Toutes les remarques, conseils sont bons si je peux progresser. Merci encore à tous pour votre aide.
J'ai rajouté le lien http://desirelabs.fr/desirelabs/ de démo.

Par ailleurs, je constate que les nuages de mon animation qui ont une vitesse spécifiée dynamiquement et unique pour chacun avec un easing linear, ralentissent leur course sur la fin.

J'ai du louper quelque chose là....

Edit : j'ai accéléré l'animation, et il se trouve qu'à chaque fois qu'un nouvel objet est généré, les précédant ralentissent.

Edit 2 : Pour la décélération, j'ai compris d'où ça vient -> A chaque passage dans la boucle, vu que la distance a diminué entre le point de départ et le point d'arrivée, mais pas la durée, l'objet ralentit CQFD.
Modifié par neovea (29 Mar 2013 - 13:35)
Hello.

Honnêtement, vu ton animation, je passerais à ta place par un SVG animé, voir un bon vieux .gif des familles en optimisant bien le poids.

Sinon, pour des animations en JS un peu plus smooth, tu peux déjà voir du côté de requestAnimationFrame à la place de setTimeout.
Florian_R a écrit :
Hello.

Honnêtement, vu ton animation, je passerais à ta place par un SVG animé, voir un bon vieux .gif des familles en optimisant bien le poids.

Sinon, pour des animations en JS un peu plus smooth, tu peux déjà voir du côté de requestAnimationFrame à la place de setTimeout.


Ah en voilà une fonction qui me plait ! J'ai regardé un peu les docs dispo à droite à gauche et ça semble correspondre à ce que je recherche. Même si j'ai plus ou moins résolu mon problème, ça va m'être très utile.

Pour SVG, c'est une techno que je ne maitrise pas encore, je découvre depuis cette semaine à peine. Je ne parviens pas à savoir si c'est vraiment plus léger. J'ai testé en générant un svg à partir d'un fichier vecto. Le résultat n'est pas léger léger. Donc bon après, quid de savoir si ça fonctionne comme dans flash avec les occurence d'un même symbole, et si oui, si je peux m'amuser à donner des paramètres aléatoires à ces derniers sans que ça pose de souci. Si oui, ça vaut peut être le coup que je me penche dessus, ce sera du temps et des ressources gagnées pour la suite.

Après c'est nivreau gestion de la part des différents navigateurs, car visiblement il y a encore quelques incompatibilités d'après ce que j'ai lu ça et là. Ce qui fait que je n'ai pas encore franchi le pas.

Le gif, non merci, je suis pas un fan des franges et des dégradés caca. Et le png reste nettement plus léger dans ce cas précis.

Hermann a écrit :
Si ce sont des animations simples, voir du côté des transitions CSS (qui permet d'obtenir des animations interpolées) : http://www.alsacreations.com/tuto/lire/873-transitions-css3-animations.html
Voire CSS animation et transformation mais attention aux implémentations..


En effet j'aurais préféré n'avoir à jouer qu'avec CSS (c'est déjà plus mon domaine), mais là je suis en train de m'attaquer à une animation plus complexe. Je ne sais pas si je vais réellement pouvoir faire tout ce que je souhaite sans une touche de Js. Mais je vais faire en sorte de me servir un max de css, dans la mesure du possible.
Salut, en fait, ton problème n'est pas un problème de poids des images ou de performances dans le sens du temps de chargement. D'après ce que je comprends, tu parle de performances en terme de fluidités des animations.

Alors, deux choses:

1. Il faut réussir idéallement à garder un ratio de 60 frames par secondes. Utilise le Chrome Devtools en mode "timeline" pour étudier le temps que prend chaque frame à s'afficher. Et étudie les sections qui explosent la limite de 60 frames.

2. Tu semble avoir un problème de fuite de mémoire ("memory leak") puisque tu dis que ton navigateur est moins fluide après avoir laissé rouler ton animation. À ce moment, regarde du côté des "Heap snapshot" dans le devtool de Chrome pour être en mesure de plus efficacement détecter la fuite de mémoire. Tu peux aussi regarder l'écran de l'utilisation de la mémoire près de la timeline - mais je trouve l'outil moins précis.

Bon, c'est une réponse vague. Mais la performance est une science complète et longue à maîtriser. J'espère t'avoir au moins pointer vers des outils qui t'aideront à détecter le problème; et en recherchant sur ces sujets/outils sur google, tu en apprendras beaucoup plus.

N'hésite pas à suivre la formation de Code Academy sur le Chrome Devtools, il y a quelques cours sur les problèmes de performances en particuliers. C'est un bon endroit pour commencer.
Après un audit rapide. Tu semble avoir une fuite de mémoire chaque fois que créé et supprime un nuage. Assure toi de supprimer toutes les références au noeud DOM contenant un nuage après l'avoir retiré du DOM.
Merci pour cette réponse très complète SBoudrias. Je regarde du côté de la timeline mais rien ne s'affiche du tout (events, frame, memory).

Je suis en train d'étudier la solution requestAnimationFrame. Je pense que pour générer et gérer les mouvements de mes éléments c'est ce qui sera le plus adapté, mais j'en suis encore au stade découverte de cette fonction.

Quand tu dis de "supprimer toutes les références au noeud DOM", qu'entends tu plus exactement ?

PS : excellent le lien de la code academy
Modifié par neovea (30 Mar 2013 - 15:18)
`requestAnimationFrame` est utile, mais ce n'est pas une solution magique non plus. Dans ton cas, le problème est vraiment la fuite de mémoire. D'autres choses pourraient être optimisées, mais présentement les animations entrent très bien dans la quantité de frame disponible par seconde - alors tu n'as pas besoin de sur-optimisé ton code à ce niveau là (principalement car la différence ne sera pas visible).

Dans l'onglet timeline, tu dois cliquer l'icône "record" pour obtenir du contenu. Ce n'est pas un onglet persistant comme le network; principalement parce que tu veux prendre seulement une section de ton animation et l'étudier. Alors tu vas enregistrer 10-15 secondes d'une animation, et ensuite tu l'étudie en détail.

neovea a écrit :
Quand tu dis de "supprimer toutes les références au noeud DOM", qu'entends tu plus exactement ?


En javascript, tant qu'une référence (variable, objet) est encore dans le scope d'une fonction, elle ne pourra pas être supprimée par le "garbage collector" et libérer l'espace mémoire qu'elle utilise.


---------------------------

J'ai copié ton projet sur jsbin : http://jsbin.com/ehufok/5
Tu devrais toujours fournir des exemples minimaux sur un site comme jsBin ou jsFiddle si tu veux de l'aide plus spécifique - principalement en javascript.
Modifié par SBoudrias (30 Mar 2013 - 17:07)
Bon alors, ton bug est vraiment simple. Il est dans ta fonction `del`. Tu ne retire jamais tes nuages parce que ta condition est toujours `false`, alors les éléments s'accumulent.
SBoudrias a écrit :
Bon alors, ton bug est vraiment simple. Il est dans ta fonction `del`. Tu ne retire jamais tes nuages parce que ta condition est toujours `false`, alors les éléments s'accumulent.


J'ai un doute là. Je viens de placer un alert() juste dans ma condition, elle renvoit bien un message quand le nuage est effacé. Ou alors j'ai mal compris.

Au passage j'ai édité mon code
/* Script de génération d'images, animation, suppression */

var i = 0;
var screenWidth = parseInt($('body').innerWidth());



function dragndrop() {
	if($('#hole').hasClass('dropped')){
		$('#seed').animate({opacity : 0},500); 
	}

	$( "#seed" ).draggable();	

	$( "#hole" ).droppable({
		drop: function( event, ui ) {
		$( this )
		  .addClass( "dropped" );
		}
	});
	setTimeout("dragndrop()",500);
}


function cloudGen(){

	do{ var haut = Math.floor(Math.random()*1000) } while(haut <= 5 || haut >= 65);
	do{ var largeur = Math.floor(Math.random()*1000) } while(largeur <= 50 || largeur >= 120);
	var frequence = 1000*Math.floor(Math.random()*10);
	var hauteur = (largeur/1.923);
	var opacite = 1;

	if(i <= 5){
		var vitesse = 700;
		do{ var gauche = Math.floor(Math.random()*1000) } while(gauche <= 5 || gauche >= screenWidth);
		
	}
	else{
		var vitesse = 1;
		var gauche = -75;
	}

	document.getElementById('space').innerHTML += '<div class="nuage nuage_'+i+'"></div>';
		
	$('#space .nuage_'+i).animate({opacity : opacite},vitesse);
	$('#space .nuage_'+i).css("top", haut);	
	$('#space .nuage_'+i).css("left", gauche);
	$('#space .nuage_'+i).css("width", largeur);
	$('#space .nuage_'+i).css("height", hauteur);

	i++;
	setTimeout("cloudGen()",frequence);
}


function cloudDel(){
	$('#space .nuage').each(function(){
		if($(this).css("left").substr(0,4) >= screenWidth){
			$(this).remove();
			//alert('true');
		}
	});
	setTimeout("cloudDel()",1000);
}


function cloudMove(){
	$('#space .nuage').each(function(){

		var position = parseInt($(this).css("left"));
		var duration = 50000;
		
		if($(this).hasClass('animated')){
			var multiplicator = position/screenWidth;
			var speed = Math.round(duration-(duration*multiplicator));
			
			$(this).addClass('animated');
			$(this).animate({left : screenWidth}, speed, "linear");
		}


		if(!$(this).hasClass('animated')){
			var multiplicator = screenWidth/screenWidth;
			var speed = duration;

			$(this).animate({left : screenWidth}, speed, "linear");
		}

		$(this).addClass('animated');
		

	});
	setTimeout("cloudMove()",100);
}



function swing(){
	$("#seed .seed").ready( function() {

		var top = parseInt($("#seed .seed").css("top"));
		$("#seed .seed").animate({top : 20},800, "swing");
		$("#seed .seed").animate({top : -20},800, "swing");

	});
	setTimeout("swing()",1600);
}



$(document).ready(function(){

	swing();
	cloudDel();
	cloudGen();
	cloudMove();
	dragndrop();


});


et avec la fonction swing, dès qu'un nuage est généré, le mouvement provoqué par cette fonction s'arrête, puis reprend. Pourtant je ne vois pas de dépendance entre les deux.
Modifié par neovea (02 Apr 2013 - 10:01)
Un petit up car la gestion du multi settimeout ou setinterval est un désastre. Personne n'a jamais eu ce problème ?
J'ai trouvé !!!!
En fait le problème se situe au niveau du DOM -> Mes fonctions de gestion des nuages parcourent régulièrement le DOM et donc la div qui englobe tout, à savoir #space, laquelle contient également ma div #seed.

J'ai fait le test et j'ai mis ma div #seed à l'extérieur de la div #space, et paf ! ça fait des chocapics ! Plus de ralentissement de l'animation de #seed !
Pages :