Un Infinite slideshow en quelques lignes de jQuery

Cet article a 284 jours. Il commence à dater, lisez-le donc en gardant son âge en tête ! Merci

Un Slideshow sur une page d’accueil, c’est joli, c’est à la mode, mais c’est souvent lourd à intégrer. Il vous faudra des compétences certaines en jQuery, ou utiliser des plugins déjà prêts.
Aujourd’hui je vous propose un tutoriel pour créer un infinite slideshow en quelques lignes de code.

Je vous ai promis, via Twitter, un « dossier-tutoriel » sur la création d’un slideshow de A à Z avec quelques options sympa. Cet article ne fait pas partie du dossier, il n’a pas grand chose à voir, il s’agit simplement de vous présenter une solution enfantine avec une petite dose de HTML, CSS et jQuery.

L’effet infinite

Cet effet donne l’impression que votre slideshow ne se termine jamais, il tourne en boucle indéfiniment sans jamais revenir en arrière.
Pour se faire, il suffit de placer l’image que l’on vient de visualiser en fin de liste à chaque défilement d’image, comme sur le schéma suivant :

L'image 1 qui vient de laisser place à l'image 2 passe en fin de liste d'images

À chaque fois qu’une image vient d’être vue et laisse place à l’image suivante, elle est placée en fin de liste afin de créer une boucle sans fin.

La structure de base

Une division contenant une liste d’images suffira pour notre tutoriel.

<div class="slideshow">
	<ul>
		<li><img src="image1.jpg" alt="" width="350" height="200" /></li>
		<li><img src="image2.jpg" alt="" width="350" height="200" /></li>
		<li><img src="image3.jpg" alt="" width="350" height="200" /></li>
		<li><img src="image4.jpg" alt="" width="350" height="200" /></li>
	</ul>
</div>

J’utilise ici une liste non ordonnée, mais un groupe de figure et figcaption peut aussi faire l’affaire.
Je vous laisse remplir les textes alternatifs ;)

Une fois cette structure en place, il nous faut la styler pour lui donner l’apparence du slideshow.

Les styles de bases

Notre conteneur doit posséder une largeur fixe, et cacher le débordement du contenu.
Dans le dossier en cours de préparation dont je parlais en début d’article, nous procèderons de manière plus « propre » en prenant en compte l’activation, ou non, de JavaScript. Mais passons, ici faisons plus simple.

.slideshow {
   width: 350px;
   height: 200px;
   overflow: hidden;
   border: 3px solid #F2F2F2;
}
.slideshow ul {
    /* 4 images donc 4 x 100% */
   width: 400%;
   height: 200px;
   padding:0; margin:0;
   list-style: none;
}
.slideshow li {
   float: left;
}

Rien de compliqué ici : on donne les dimensions aux conteneurs, on annule quelques styles par défaut (marges, puces de liste), puis on fait flotter les éléments. On peut également utiliser display:inline-block.

Un petit coup de jQuery

La première fois que j’avais écris ce code, j’ai utilisé la bibliothèque jQuery 1.5.1. Quand on voit le poids de la bibliothèque en version 1.7+, je me suis dit qu’on pouvait rester sur la 1.5.
Voici le code, je vous l’explique après.

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
 
<script type="text/javascript">
   $(function(){
      setInterval(function(){
         $(".slideshow ul").animate({marginLeft:-350},800,function(){
            $(this).css({marginLeft:0}).find("li:last").after($(this).find("li:first"));
         })
      }, 3500);
   });
</script>

Un grand coup d’explications

Voici quelques explications pour les personnes les moins aguerries en jQuery, car le code est court, mais quelque peu condensé.


   $(function(){
      […]
   });

Cette partie englobant notre fonction permet de vérifier que le document est bien chargé, c’est l’équivalent de la fonction ready().


   setInterval(function(){
      […]
   }, 3500);

Cette partie permet de définir une action qui va se répéter à intervalle régulier. La fonction setInterval() prend en paramètres une fonction anonyme (ou le nom d’une fonction existante), et le délai en milliseconde entre chaque exécution de la fonction. Dans notre cas, nous définissons une fonction anonyme avec function(){} et définissons la répétition à 3,5 secondes.
Petite parenthèse : il arrive très souvent de croiser la syntaxe var t = setInterval(). Cette syntaxe permet l’annulation de la répétition grâce à la fonction clearInterval(t).

Le tronçon qui va suivre est un peu plus complexe à comprendre car il utilise massivement le principe de chaînage de jQuery. Il faut imaginer qu’à chaque fois qu’un point apparait, on utilise le précédent objet jQuery pour le manipuler.

Exemple :

$('ul').find('li').css('color', 'red').filter(':first').css('color','green');

Nous commençons par « sélectionner » nos éléments ul dans notre document, puis nous ciblons les éléments li, la fonction find() nous retourne un objet jQuery, puis nous appliquons un style particulier sur ces éléments. La fonction css() nous retourne le même objet jQuery que précédemment, ce qui nous permet de le manipuler à nouveau et d’aller chercher uniquement le premier élément li grâce à la fonction filter() qui retourne également un objet jQuery auquel on va appliquer d’autres styles, etc.
Il faut savoir que la plupart des fonctions jQuery permettent ainsi le chainage.

Reprenons donc sur ce fameux tronçon :


 $(".slideshow ul").animate({marginLeft:-350},800,function(){
   $(this).css({marginLeft:0}).find("li:last").after($(this).find("li:first"));
 })

Nous commençons par cibler notre ul que nous allons faire bouger vers la gauche grâce à une animation qui va appliquer une marge négative de 350px en 0,8 secondes (animate(marginLeft:-350, 800)). La fonction animate() permet d’exécuter une fonction de callback, il s’agit d’une fonction exécutée lorsque animate() retourne « complete » : quand l’animation est terminée donc :p
Cette fonction de callback, nous la déclarons juste après le paramètre de durée de l’animation.
Cette fonction exécute ce qui suit :

$(this).css({marginLeft:0}).find("li:last").after($(this).find("li:first"));

De quoi se faire plaisir en terme de chainage.
$(this) représente chacun des .slideshow ul que pourrait retourner notre objet jQuery (oui, il pourrait y avoir plusieurs slideshow sur votre page).
Nous partons donc de notre élément ul auquel nous supprimons la marge négative récemment attribuée par l’animation, puis nous allons chercher le dernier li de notre liste (find("li:last")) et nous y plaçons juste après (after()) le premier élément de notre liste ($(this).find("li:first")).
La fonction after() a une syntaxe assez particulière, j’en conviens, je vous invite donc à lire la documentation pour plus d’informations à son sujet.

Tout ce morceau de code est exécuté quasiment en même temps à la fin de l’animation. À chaque défilement d’un slide, on prend le premier élément de la liste, on le place à la fin, et on annule la marge négative que l’on vient de donner à notre liste. C’est invisible pour l’oeil.

J’espère que les explications ne sont pas plus complexes que le code :D

Voir la démonstration

Je vous recommanderais presque de ne pas suivre ce tutoriel pour de la production. En effet, en terme d’accessibilité (et même d’ergonomie) l’absence de contrôle sur l’animation est perturbante. (entre autres défauts)
Le prochain dossier devrait prendre en compte ces critères.
À venir donc !

Méthode 2

Une seconde méthode, assez semblable mais plus simple à comprendre, nous a été proposée par Thierry. Je vous place le code jQuery :

(function($){
  setInterval(function(){
    $(".slideshow ul li:first-child").animate({"margin-left": -350}, 800, function(){
        $(this).css("margin-left",0).appendTo(".slideshow ul");
    });
  }, 3500);
})(jQuery);

Les changements se situent sur le premier sélecteur, afin que l’animation ne se fasse que sur le premier élément de la liste (li:first-child).
Celui-ci subit un décalage de 350 pixels, les autres li suivent le mouvement.
Une fois cette animation terminée, la fonction appendTo() permet d’insérer ce premier élément en le plaçant à la suite des autres éléments du conteneur (.slideshow ul), ici à la fin des différents li.

46 commentaires et un trackback sur “Un Infinite slideshow en quelques lignes de jQuery”

  1. William dit :
    13 août 2012

    Merci pour cette petite démonstration. Comme quoi on a pas forcément de choisir un plugin énorme pour ce genre de fonctionnalité.

    Par contre je vais attendre le dossier suivant ^^
    L’autoplay c’est le mal :p

    J’avais commencé un petit truc ici (si ça peut aider) : http://jsfiddle.net/Remwideco/yuxdk/

  2. Geoffrey dit :
    13 août 2012

    Je suis bien d’accord avec toi :)
    Merci pour ton avis d’expert en accessibilité.

    Concernant le dossier une bonne partie de mon script est déjà opérationnel, le plus dur c’est d’expliquer le code et les choix.
    Merci pour ton script en tout cas, je vois qu’on a la même approche (overflow, création des éléments de contrôle avec JS uniquement).

    À bientôt et bonne semaine.

  3. Ilycite dit :
    13 août 2012

    En gros cet article c’est « Regardez ce que je ne veux pas que vous fassiez » :D . Mais sinon le principe est simple et sympa, fallait y penser

  4. Geoffrey dit :
    13 août 2012

    Ah ah :D
    C’est presque ça.
    Disons que si c’est pour faire des choses aussi simples, il ne faut pas se prendre le chou avec des plugins trop lourds et complexes.
    Par contre effectivement lorsque les choses sont aussi simples, elles ont quelques défauts, et on verra ensemble comment les corriger :)

    Il faut prendre ça comme un teasing :p

  5. AoSiX dit :
    13 août 2012

    Un petit truc à corriger : « l’absence de contrôle sur l’animation ET perturbante. »

    Ceci mis à part, c’est un très bon tuto. On pense souvent à tord que c’est difficile de faire de bons effets… mais non :) Merci beaucoup !

  6. Geoffrey dit :
    13 août 2012

    Merci pour la correction :)
    Bonne journée.

  7. GeekPress dit :
    13 août 2012

    Juste énorme. On avait fait un truc un carrousel infini pour un client, mais c’était avec beaucoup plus de lignes de code =D

    Bien joué !

  8. Screenfeed dit :
    14 août 2012

    Hmm… Pas très W3C cette fermeture de balise script =D #JAimeFoutreLaMerde

  9. Geoffrey dit :
    14 août 2012

    @Screenfeed : oui bien vu :) Merci

    @GeekPress : merci m’sieur. Après tout dépend du besoin. Si des styles ou éléments sont créés avec JS ça prend vite plus de place :)

  10. Nicolas dit :
    14 août 2012

    Yay très intéressent, merci beaucoup Geo :-)

  11. corto dit :
    14 août 2012

    Niveau slideshow infini avec controle je recommande : http://www.philparsons.co.uk/demos/box-slider/

  12. Geoffrey dit :
    14 août 2012

    @Nico : Merci :)

    @corto : Merci pour cette ressource qui collerait peut-être davantage avec ma dernière sélection de slideshow.
    Je vais voir pour l’ajouter.

  13. Davy dit :
    22 août 2012
  14. Loeline dit :
    23 août 2012

    Bonjour ^^
    Alors déjà bravo pour ce que vous avez fait, c’est super :)
    J’ai essayer de l’installer sur mon forum, sauf que les images ne défilent pas :/ Si vous pouviez m’aider ce serait super ^^
    Merci !

  15. Geoffrey dit :
    23 août 2012

    Bonjour,

    Merci.
    Il me faudrait un lien pour pouvoir tester :)
    Bonne journée.

  16. Loeline dit :
    23 août 2012

    Ok ^^’
    http://art-graphique.forumsactifs.com/ (le slide est dans la page d’accueil)

  17. Geoffrey dit :
    23 août 2012

    Re,
    Je ne vois pas le script JS dans ton code. Je sais que Forum-Actif a un peu de mal avec ça. Comment as-tu procédé ?

  18. Loeline dit :
    23 août 2012

    Alors j’ai mis ce code dans la partie html (Page d’accueil) :

    Après le CSS dans la feuille de Style :

    .slideshow {
    width: 420px;
    height: 150px;
    overflow: hidden;
    border: 3px solid #F2F2F2;
    }
    .slideshow ul {
    /* 4 images donc 4 x 100% */
    width: 400%;
    height: 150px;
    padding:0; margin:0;
    list-style: none;
    }
    .slideshow li {
    float: left;
    }

    Et le Jquery dans une page JavaScript :

    $(function(){
    setInterval(function(){
    $(« .slideshow ul »).animate({marginLeft:-350},800,function(){
    $(this).css({marginLeft:0}).find(« li:last »).after($(this).find(« li:first »));
    })
    }, 3500);
    });

  19. Loeline dit :
    23 août 2012

    Dsl le HTML ces pas afficher, bref je l’ai mis dans Panneau admin, affichage, généralité et message sur la page d’accueil ^^’

  20. Geoffrey dit :
    23 août 2012

    Essaye de mettre le morceau de code JavaScript à la fin de ton document : http://art-graphique.forumsactifs.com/16415.js qui doit se trouver dans les scripts de ton panneau d’admin.

    Parce que je te confirme que le script n’est pas présent pour le moment. (supprimé au moment de la sortie du code, même si présent dans le champs Message d’accueil.)

  21. Loeline dit :
    23 août 2012

    J’ai pas compris, désolée :s
    Votre JQuery fallait bien le mettre dans une page JavaScript ? Si oui ces ce que j’ai fait, mais après j’ai rien fait d’autre.. :/

  22. Geoffrey dit :
    23 août 2012

    Il est possible de placer le code JavaScript directement après le code HTML (entre balise script), ou placer le code dans une feuille JavaScript, sans oublier de charger cette feuille à l’aide de la balise script.

    Or ici je ne trouve pas le code, même dans les fichiers JavaScript externe du forum.

    Donc si tu as enregistré le code dans une feuille JS, il faut charger cette feuille dans le HTML. Là par contre je ne sais pas comment Forum-Actif gère ça :/

  23. Loeline dit :
    23 août 2012

    J’ai essayer de mettre le code JavaScript entre les balise script, directement dans ma page html, mais sa ne fonctionne pas :/
    Si je ne peut pas, j’essaierai de trouver un truc aussi simple mais que Forumactif accepte ^^’

  24. Geoffrey dit :
    23 août 2012

    Désolé, je ne peux pas t’aider davantage, ça fait longtemps que je n’ai pas touché à FA.

  25. Loeline dit :
    23 août 2012

    Ces n’est pas grave =) Merci quand mm !
    Et tu fait du super travail, bravo :)

  26. Geoffrey dit :
    23 août 2012

    Merci ! :)
    Bon courage dans le développement de ton forum !

  27. Dan dit :
    30 août 2012

    Alors là !
    je suis une bille en Jquery… mais je potasse !
    Ton script est une petite merveille (pour moi).
    Installé en 2 minutes et ça fonctionne au poil.
    Grand merci à toi ;-)

  28. tm dit :
    31 août 2012

    Salut,

    Sympa comme tuto !
    On peut encore simplifier un « chouia » en faisant le « animate » sur le premier « li » puis en le rajoutant simplement à la liste !

    http://jsfiddle.net/thierrymichel/2fNsR/

    tm

  29. Geoffrey dit :
    31 août 2012

    Hello,

    Oui effectivement ce n’est pas bête, c’est un peu plus simple à comprendre en plus.

    Puis-je la rajoute dans l’article avec ton accord et un lien vers ton site web (me faudrait l’URL) ?

    Merci pour ta suggestion.
    Bonne journée.

  30. tm dit :
    2 septembre 2012

    Salut Geoffrey,
    Aucun souci. Avec plaisir même !

    tm

  31. Geoffrey dit :
    2 septembre 2012

    Hello,

    Merci bien, c’est fait :)

    Au plaisir de tes interventions.
    Bonne soirée.

  32. always dit :
    1 novembre 2012

    merci de nous permettre de nous former

  33. phasm dit :
    29 novembre 2012

    Merci pour ce petit code bien pratique et qui semble répondre à ce que je cherchais.

    Malheureusement, il me reste un petit souci à régler dans mon cas de figure assez particulier.

    Je vais essayer de résumer et simplifier, car ma page est à la base assez complexe et déjà truffée de jQuery et JS.

    J’utilise de nombreux slideshows sur ma page, mais au départ ils sont tous cachés.
    En cliquant sur un onglet, une div se déplie sous celui-ci (grâce à jQuery) et laisse apparaître le slideshow correspondant.
    Si je clique de nouveau sur ce même onglet, la div se referme.
    Mais si la div 1 est ouverte et que je clique sur l’onglet 2, la div 1 se referme et la div 2 apparaît (contenant le slideshow 2).

    C’est ici que survient mon problème : dans ce cas de figure le slideshow 2 se met bien en route, mais il ne respecte plus la vitesse de défilement que je lui indique, ça va beaucoup trop vite, les slides s’enchaînent les unes à la suite des autres.

    Il est possible que mon problème vienne du fait qu’au sein de mon code, dans une même instruction, je demande à la fois un clearInterval et un setInterval ? Je ne suis pas un spécialiste…

    Ci-dessous une copie hyper simplifiée de mon script.
    L’étape qui me pose problème correspond à la deuxième condition (= premier « else if »).

    Une idée ?

    $(document).ready(function(){
    	$('.tabMenuWB > li:not(.blind, .lastblind)').click(function(){
    		if (($(this).hasClass("close")) && (image != 1)){
    			
    			  twb = setInterval(function(){
    				 $(".framebox ul.multishow").animate({marginLeft:-605},800,function(){
    					$(this).css({marginLeft:0}).find("li:last").after($(this).find("li:first"));
    				 })
    			  }, 1500);
    		}
    		else if (($(this).hasClass("close")) && (image != 0)){
    			window.clearInterval(twb);
    			
    			  twb = setInterval(function(){
    				 $(".framebox ul.multishow").animate({marginLeft:-605},800,function(){
    					$(this).css({marginLeft:0}).find("li:last").after($(this).find("li:first"));
    				 })
    			  }, 1500);
    		}
    		else if (($(this).hasClass("open")) && (image != 0)){
    			window.clearInterval(twb);
    			
    		}
    	});
    });
  34. Geoffrey dit :
    29 novembre 2012

    Bonsoir,

    À la suite de window.clearInterval(twb); essayez de rajouter twb = null; pour voir si le problème persiste.

    J’ai déjà rencontré ce souci également sur un projet avec beaucoup de JS.

    Bonne soirée ;)

  35. Claire dit :
    10 décembre 2012

    super pratique ce petit tuto ! Faire un slideshow a enfin l’air rapide et facile !

  36. Julien dit :
    16 décembre 2012

    Bonsoir,
    J’ai essayé ce petit code et ça marche à merveille et je souhaite changer le design un peu à ma sauce.
    J’ai rajouté (sans trop savoir si c’était bien sémantiquement correct) des span entre chaque li afin de faire une fine ligne séparatrice entre chaque image.
    Sauf que le script ne semble pas vouloir faire saute mouton au dessus des span qu’il ne reconnaît pas … Est il possible d’inclure (ou d’exclure ?) ces spans afin que le slide se fasse d’image en image, et ignore donc les span séparateurs ?

  37. Geoffrey dit :
    16 décembre 2012

    Bonjour Julien,

    Ce n’est pas très valide tout ça. Un élément ul ne peut contenir que des éléments enfants directs li.

    Je ne sais pas ce que tu souhaites obtenir au final comme aspect du coup je ne vois pas quoi te conseiller.

    Pour information la fonction jQuery next() te permet de sélectionner le frère suivant. Dans ton code il s’agit d’un span et non d’un li, du coup ça plante.

  38. Marti dit :
    9 janvier 2013

    Merci pour ce tuto qui fait une bonne base de travail pour le script un peu plus compliqué dont j’ai besoin! :)

  39. Loïc L. dit :
    25 février 2013

    Merci pour ton tuto !! Je me suis amusé à changer le sens déplacement du slide. Etant débutant en jQuery, j’ai placé l’ul en absolute par rapport au div, et lui ai assigné un right à 0 (tout ça dans le css).Et enfin, remplacé « margin-left » par « margin-right » dans la fonction jQuery. Si il y a plus simple je souhaiterai connaître l’astuce. Merci par avance. :)

  40. Geoffrey dit :
    25 février 2013

    Salut Loïc !
    Ça me semble très une bonne manière de procéder a priori.
    Il y a toujours plusieurs solutions à un problème, mais la tienne me semble ok.
    Bonne continuation !

  41. yakmandji dit :
    18 mai 2013

    Salut tout le monde. Merci pour ce tuto sympa. Et sympa ce site que je viens de découvrir.
    J’aimerais l’utiliser pour un projet.
    mais j’aurais deux petites questions.
    Est ce qu’en rajoutant deux div sur les cotés avec du « onclick » dans le Javascript suffirait pour rajouter des boutons et obtenir un control du slide?

    Et est ce que en agrandissant la fenêtre principal, cela suffirait pour voir plus de un élément défiler à la fois.

    Merci par avance.

  42. Geoffrey dit :
    19 mai 2013

    Hello.
    Le contrôle du slide peut effectivement s’obtenir grâce à deux boutons injectés grâce à JS.
    Cependant le JS actuellement proposé ne permet pas de stopper l’animation ou de faire défiler plus d’un élément à la fois.
    La modification du code ne serait pas très très complète si tu as saisi celui-ci.
    Bonne continuation.

  43. yakmandji dit :
    21 mai 2013

    Merci pour ta réponse Geoffrey.
    En fait j’ai réussis à placer mes deux boutons pour un control à gauche et à droite.

    par contre j’ai retiré la partie « infinite » qui fait repasser l’image de l’autre coté.
    J’ai mis à la place l’impossibilité de continuer à slider quand il n’y a plus d’image et donc il faut cliquer de l’autre coté.

    Je t’explique où j’ai bloqué :

    Quand on clic sur mon bouton et que ça slide de droite à gauche tout est bien invisible à l’oeil et le li de gauche repasse à la fin.

    Par contre quand on slide de gauche à droite, étant donné qu’il n’y a plus d’image à gauche. ça laisse du blanc le temps de l’animation. Et après on voit bien l’image se mettre à gauche. mais en attendant on a vue qu’il manquait une image à gauche qui est venu se rajouter à la fin de la fonction « animate. »

    l’idéal serait que la fenêtre principal ul soit centré sur le milieu des li. mais j’ai pas réussis… Si tu as une idée. Si je trouve en attendant je posterais.
    merci encore.

  44. yakmandji dit :
    21 mai 2013

    Bon je reviens aux nouvelles. J’ai trouvé la solution :-)
    - la partie du code qui fait l’infinite il faut la mettre avant la fonction animate.
    - et il faut changer le reset à 0 du marginLelft en -220 pour éviter l’espace blanc.
    - ensuite rajouter une fonction .click avec deux bouton.
    - et j’ai rajouter un setimeout pour éviter les multiple clics.
    ça fais un carousselle bien sympa qui fonctionne des deux coté en infinite.

    Si tu veux mettre le code pour un interressé y a pas de soucis. Merci encore pour le tuto.

  45. Geoffrey dit :
    21 mai 2013

    Hello,

    Oui effectivement il suffisait de changer l’ordre d’exécution des fonctions pour le sens opposé :)
    Concernant le code je tiens à le laisser au plus simple sur l’article, mais je te remercie de ta proposition de partage.

    J’ai un article en cours de rédaction depuis 5 ou 6 mois sur la création d’un slideshow de A à Z (en considérant l’aspect responsive), du coup cet aspect sera traité.
    Bonne continuation !

  46. Béatrice dit :
    22 mai 2013

    Bonjour à tous,

    En tout premier lieu, bravo et merci à Geoffrey pour son travail. L’adaptation et la mise en œuvre est miraculeusement simple et fonctionnelle.

    Je me tourne vers toi, Yakmandji, pourrais-tu m’aiguiller pour rendre opérationnels les boutons next et preview.
    Voici le lien de mon test carrousel :
    http://www.bleu-atlantique.eu/FastTest/
    Un grand merci par avance.

Laisser un commentaire

Certains codes HTML ne sont pas échappés automatiquement. Pour afficher du code dans votre commentaire, merci d'échapper vos chevrons en utilisant "&lt;" et "&gt;" en lieu et place de "<"" et ">".

Il est difficile de proposer un support pour tous les articles de ce blog. En ne fournissant pas un moyen de consulter votre code bogué, vous vous assurez de ne pas avoir de réponse adaptée.

Les sites qui en parlent

 
Le studio web