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 😀

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.