Développement Web

Tutoriel : Créer un slider d’images en JavaScript pur

12 دقائق للقراءة

Prérequis

  • Niveau : bases HTML/CSS/JS, classes JS (cf. manipuler le DOM).
  • Outils : VS Code + Live Server, navigateur moderne.
  • Temps estimé : 1 h.

Pourquoi un slider en JS pur ?

Les bibliothèques (Swiper, Slick) ajoutent 20 à 50 Ko à votre page. Pour un simple carrousel, JavaScript natif suffit largement et reste maintenable, performant et sans dépendance. Vous gardez le contrôle complet du comportement et de l’accessibilité.

Le slider (carrousel) : composant incontournable

Un slider d’images est un diaporama interactif que l’on retrouve sur presque tous les sites. Voici comment en créer un en JavaScript pur, sans bibliothèque externe.

Structure HTML

<div class="slider">
    <div class="slides">
        <div class="slide actif">
            <img src="slide1.jpg" alt="Formation Développement Web">
            <div class="legende">
                <h3>Développement Web</h3>
                <p>Apprenez HTML, CSS et JavaScript</p>
            </div>
        </div>
        <div class="slide">
            <img src="slide2.jpg" alt="Marketing Digital">
            <div class="legende">
                <h3>Marketing Digital</h3>
                <p>Maîtrisez les réseaux sociaux</p>
            </div>
        </div>
        <div class="slide">
            <img src="slide3.jpg" alt="Cybersécurité">
            <div class="legende">
                <h3>Cybersécurité</h3>
                <p>Protégez vos systèmes</p>
            </div>
        </div>
    </div>
    
    <!-- Flèches de navigation -->
    <button class="nav-btn prev">❮</button>
    <button class="nav-btn next">❯</button>
    
    <!-- Points indicateurs -->
    <div class="dots">
        <span class="dot actif" data-index="0"></span>
        <span class="dot" data-index="1"></span>
        <span class="dot" data-index="2"></span>
    </div>
</div>

CSS du slider

.slider {
    position: relative;
    width: 100%;
    max-width: 900px;
    margin: 0 auto;
    overflow: hidden;
    border-radius: 12px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}

.slides {
    display: flex;
    transition: transform 0.5s ease;
}

.slide {
    min-width: 100%;
    position: relative;
}

.slide img {
    width: 100%;
    height: 450px;
    object-fit: cover;
    display: block;
}

/* Légende sur l'image */
.legende {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 30px;
    background: linear-gradient(transparent, rgba(0,0,0,0.7));
    color: white;
}

.legende h3 { font-size: 24px; margin-bottom: 5px; }
.legende p { opacity: 0.9; }

/* Flèches */
.nav-btn {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: rgba(255,255,255,0.8);
    border: none;
    width: 45px;
    height: 45px;
    border-radius: 50%;
    font-size: 20px;
    cursor: pointer;
    transition: background 0.3s;
    z-index: 10;
}

.nav-btn:hover { background: white; }
.prev { left: 15px; }
.next { right: 15px; }

/* Points indicateurs */
.dots {
    position: absolute;
    bottom: 15px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 8px;
    z-index: 10;
}

.dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: rgba(255,255,255,0.5);
    cursor: pointer;
    transition: background 0.3s;
}

.dot.actif { background: white; }

/* Responsive */
@media (max-width: 768px) {
    .slide img { height: 250px; }
    .legende h3 { font-size: 18px; }
}

JavaScript du slider

class Slider {
    constructor(élément) {
        this.slider = élément;
        this.slides = élément.querySelector('.slides');
        this.totalSlides = élément.querySelectorAll('.slide').length;
        this.dots = élément.querySelectorAll('.dot');
        this.currentIndex = 0;
        this.autoPlayInterval = null;
        
        this.init();
    }
    
    init() {
        // Flèches
        this.slider.querySelector('.prev').addEventListener('click', () => this.precedent());
        this.slider.querySelector('.next').addEventListener('click', () => this.suivant());
        
        // Points
        this.dots.forEach(dot => {
            dot.addEventListener('click', () => {
                this.allerA(parseInt(dot.dataset.index));
            });
        });
        
        // Swipe tactile (mobile)
        let touchStartX = 0;
        this.slider.addEventListener('touchstart', (e) => {
            touchStartX = e.touches[0].clientX;
        });
        this.slider.addEventListener('touchend', (e) => {
            const diff = touchStartX - e.changedTouches[0].clientX;
            if (Math.abs(diff) > 50) {
                diff > 0 ? this.suivant() : this.precedent();
            }
        });
        
        // Clavier
        document.addEventListener('keydown', (e) => {
            if (e.key === 'ArrowLeft') this.precedent();
            if (e.key === 'ArrowRight') this.suivant();
        });
        
        // Démarrer le défilement automatique
        this.demarrerAutoPlay();
        
        // Pause au survol
        this.slider.addEventListener('mouseenter', () => this.arreterAutoPlay());
        this.slider.addEventListener('mouseleave', () => this.demarrerAutoPlay());
    }
    
    allerA(index) {
        this.currentIndex = index;
        this.slides.style.transform = `translateX(-${index * 100}%)`;
        
        // Mettre à jour les points
        this.dots.forEach(d => d.classList.remove('actif'));
        this.dots[index].classList.add('actif');
    }
    
    suivant() {
        const next = (this.currentIndex + 1) % this.totalSlides;
        this.allerA(next);
    }
    
    precedent() {
        const prev = (this.currentIndex - 1 + this.totalSlides) % this.totalSlides;
        this.allerA(prev);
    }
    
    demarrerAutoPlay() {
        this.autoPlayInterval = setInterval(() => this.suivant(), 4000);
    }
    
    arreterAutoPlay() {
        clearInterval(this.autoPlayInterval);
    }
}

// Initialiser
document.addEventListener('DOMContentLoaded', () => {
    new Slider(document.querySelector('.slider'));
});

💡 Fonctionnalités incluses

  • Navigation par flèches (clic)
  • Navigation par points indicateurs
  • Swipe tactile pour mobile
  • Navigation clavier (flèches gauche/droite)
  • Défilement automatique (pause au survol)
  • Boucle infinie (revient au début après la dernière slide)

Erreurs fréquentes

Slider qui « saute » entre slides

Cause : oubli de overflow: hidden sur le conteneur, ou min-width: 100% manquant sur les slides.
Solution : appliquez bien ces deux règles. Toutes les slides doivent occuper exactement la largeur du conteneur.

Pas accessible au clavier ou aux lecteurs d’écran

Cause : les boutons n’ont pas d’aria-label, les points indicateurs ne sont pas focalisables.
Solution : ajoutez aria-label="Slide précédente" / "Slide suivante", et utilisez <button> au lieu de <span> pour les dots.

Auto-play qui continue après changement d’onglet

Cause : setInterval tourne même quand l’onglet est en arrière-plan.
Solution : écoutez document.visibilitychange et arrêtez l’auto-play si document.hidden.

Swipe tactile qui bloque le scroll vertical

Cause : touchmove consomme l’événement.
Solution : n’écoutez que touchstart + touchend (comme dans cet article), pas touchmove.

Exercice pratique

🎯 Défi : Slider pour votre site

  1. Créez un slider avec 4-5 images de vos projets ou services
  2. Ajoutez des légendes avec titre et bouton CTA
  3. Testez le swipe sur mobile (DevTools → mode mobile)
  4. Personnalisez la durée du défilement automatique
  5. Bonus : ajoutez un effet de fondu (fade) au lieu du glissement

Slider JS pur vs Swiper.js, Glide.js et Splide.js : quand basculer

Coder un slider from scratch en JavaScript pur reste pédagogique mais devient rapidement contre-productif sur un projet sérieux. Trois bibliothèques dominent en 2026 et couvrent 95 % des besoins. Swiper.js (39k+ étoiles GitHub) est la référence incontournable, utilisée par Tesla, Apple et Microsoft sur leurs sites publics. Riche en fonctionnalités : effets parallax, lazy loading, virtuel scroll, support tactile complet. La taille (≈ 130 KB minified) est conséquente — à ne charger que si vous utilisez les fonctionnalités avancées.

Glide.js (~30 KB) reste un bon compromis entre légèreté et fonctionnalités courantes (autoplay, breakpoints, transitions). Splide.js (~25 KB, accessibilité WCAG par défaut) gagne du terrain pour les sites où l’a11y est une priorité — ce qui est le cas de tout site institutionnel ouest-africain visant les marchés publics. Pour un slider basique 5-10 images sans interaction tactile complexe, le code from scratch reste le plus léger (3-5 KB). Pour un produit e-commerce sérieux, Swiper ou Splide gagnent immédiatement.

Optimisation des images du slider : srcset et lazy loading

Un slider qui charge 8 images full HD au démarrage de la page tue les performances mobile. Trois optimisations cumulables sont à appliquer systématiquement. Première optimisation : utiliser srcset et sizes pour servir des images adaptées à la résolution du visiteur. Une image de 1920px fait 350 KB en JPEG ; une image de 800px en fait 80 KB pour le même rendu sur mobile.

<img
  src="slide-800.jpg"
  srcset="slide-400.jpg 400w, slide-800.jpg 800w, slide-1600.jpg 1600w"
  sizes="(max-width: 768px) 100vw, 80vw"
  loading="lazy"
  alt="Description précise de la slide">

Deuxième optimisation : l’attribut loading="lazy" qui retarde le chargement des images hors-écran. Important : la première slide doit utiliser loading="eager" ou pas d’attribut du tout, car elle est immédiatement visible. Charger en lazy une image au-dessus du fold pénalise le Largest Contentful Paint. Troisième optimisation : préférer le format AVIF ou WebP au JPEG via une balise <picture> avec sources conditionnelles. AVIF économise 30 à 50 % de poids à qualité visuelle équivalente.

Accessibilité (WCAG 2.2) : ce qu’un slider doit absolument respecter

Un slider est l’un des composants les plus problématiques en accessibilité. Quatre règles obligatoires en 2026. Première règle : possibilité de mettre en pause l’autoplay. Un slider qui change automatiquement toutes les 3 secondes est insupportable pour un utilisateur de lecteur d’écran ou un visiteur cognitivement sensible. Ajouter un bouton play/pause visible et accessible au clavier. Deuxième règle : navigation au clavier. Les flèches gauche/droite doivent fonctionner quand le slider a le focus, et le Tab doit passer correctement entre les contrôles.

Troisième règle : annonces ARIA appropriées. Le conteneur du slider porte aria-roledescription="carousel", chaque slide porte aria-roledescription="slide" avec aria-label descriptif. La zone live aria-live="polite" annonce le changement de slide aux lecteurs d’écran. Quatrième règle : contraste suffisant des indicateurs (dots, flèches) — minimum 3:1 pour les éléments graphiques selon WCAG AA. Un dot blanc sur fond clair est invisible pour beaucoup d’utilisateurs.

Gestion mobile : swipe tactile correct

Un slider sans support tactile sur mobile est pratiquement inutilisable en 2026, où plus de 80 % du trafic web est mobile. Trois patterns techniques sont à connaître. Premier pattern : utiliser les événements pointerdown, pointermove, pointerup qui unifient mouse + touch + stylus en une seule API. Plus de complexité touchstart/mousedown séparés. Deuxième pattern : implémenter un seuil minimal de déplacement (≈ 50 px) pour distinguer un swipe d’un tap, et ajouter un seuil de vélocité pour permettre des swipes rapides courts.

Troisième pattern : ne jamais bloquer le scroll vertical de la page pendant un swipe horizontal sur le slider. Détecter l’orientation dominante du geste pendant les 50 premiers pixels, et appliquer preventDefault() uniquement si le déplacement horizontal dépasse 1,5x le déplacement vertical. Sinon, l’utilisateur ne peut plus scroller verticalement la page quand son doigt commence sur le slider. C’est l’erreur la plus frustrante des sliders mal codés.

Adaptation au contexte ouest-africain

Pour un site e-commerce ou vitrine PME basé à Dakar, Abidjan, Bamako ou Cotonou, le slider est l’élément qui pèse le plus sur les performances perçues — et donc sur le taux de rebond. Sur une 4G qui oscille entre 5 et 30 Mbps, un slider de 8 images mal optimisé ajoute 2 à 4 secondes au temps de chargement initial. Concrètement, 40 % des visiteurs partent avant que la page soit complètement chargée si elle dépasse 3 secondes selon les études Google PageSpeed.

Trois conseils pratiques. Premièrement, ne pas mettre plus de 5 slides au-dessus du fold. Deuxièmement, optimiser chaque image individuellement avec un outil comme Squoosh (gratuit, en ligne) avant l’upload — viser 80-150 KB par image. Troisièmement, tester systématiquement le slider sur un Galaxy A03 connecté en 4G locale, pas seulement sur un Mac avec fibre. Pour les techniques de validation HTML et JS modernes, voir les événements JavaScript expliqués.

Animations CSS pour transitions fluides entre slides

Le confort visuel d’un slider tient autant aux transitions qu’au contenu lui-même. Trois approches dominent en 2026 selon le rendu cible. Première approche : transform: translateX() sur le track de slides, animé via transition CSS. C’est l’option la plus performante car le navigateur peut optimiser le rendu sur le GPU. Évitez left ou margin-left qui déclenchent un reflow coûteux à chaque pixel.

.slider-track {
  display: flex;
  transition: transform 350ms cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: transform;
}
.slider-track.animating {
  pointer-events: none; /* éviter les clics pendant l'animation */
}

Deuxième approche : effet de fondu (fade) avec opacity sur les slides empilées. Plus discret visuellement, idéal pour les sites institutionnels ou les portfolios premium. Troisième approche : effets parallax (Swiper.js le fait nativement) où le contenu et l’arrière-plan se déplacent à des vitesses différentes. Joli mais coûteux en CPU sur mobile bas de gamme — à utiliser avec parcimonie en contexte ouest-africain où l’audience tourne sur Galaxy A03 et équivalents.

Critères de décision finale : faut-il vraiment un slider ?

Avant de coder ou d’intégrer un slider, posez-vous une question fondamentale : ce slider apporte-t-il vraiment de la valeur, ou est-ce un cargo cult ? Plusieurs études UX (NN Group, Baymard Institute) montrent que les sliders en haut de page d’accueil ont des taux de clics extrêmement bas — souvent 1 % sur la première slide et 0,1 % sur les suivantes. Ils consomment de la bande passante et de l’attention sans créer de conversion mesurable.

Trois cas où un slider reste justifié : galerie produit e-commerce avec navigation entre photos d’un même article (Amazon, Jumia, Konga), portfolio créatif où le swipe fait partie de l’expérience souhaitée, comparaison avant/après sur un site de service (architecte, coach sportif, dentiste). Dans les autres cas, une grille statique d’images ou un texte/CTA clair convertit mieux qu’un slider clignotant. Mesurez d’abord avec un A/B test si possible avant d’investir dans un slider complexe.

Pour les équipes qui veulent valider l’impact réel, les outils comme Hotjar, Microsoft Clarity (gratuit) ou Plausible Analytics donnent des heatmaps qui révèlent immédiatement si vos visiteurs cliquent sur le slider — ou s’ils l’ignorent et scrollent directement.

Pour les équipes qui maintiennent plusieurs sliders sur un site, centraliser le composant dans un Web Component ou un module ES6 réutilisable évite la duplication de code et facilite les évolutions futures.

Sur un angle proche

مشاركة