Personnellement, je n’aime pas les sliders ou carrousel. Je déteste arriver sur une page, commencer à lire le contenu d’une slide, pour qu’elle disparaisse de l’écran avant que je n’ai fini de la lire. Je dois alors trouver la navigation (qui est en générale assez discrète), puis recliquer sur la slide précédente pour finir ma lecture. Et si j’ai la patience d’attendre la deuxième slide, il y a de fortes chances que cette expérience se reproduise, car en général les slides ont la même quantité de contenu.

Aussi, il y a parfois sur chaque slide une belle image de fond qui pèse 2Mo à elle seule, et on va charger jQuery, une petite (ou pas) lib JS pour le slider, et le petit bout de JS maison qui va l’initialiser. Bref, c’est mauvais niveau performance, et UX. Et en plus la majorité des gens ne lisent pas toutes les slides, et stoppent à la première. Les sliders étaient à la mode il y a quelques années. Ils restent assez présents, mais j’en vois quand même de moins en moins.

Mais parfois, on a besoin de pouvoir présenter du contenu sans prendre trop de place verticalement. Dans ce cas, un simple défilement horizontal peut suffire. Par exemple, pour une section “Articles sur le même sujet”, un petit défilement horizontal manuel peut faire l’affaire. Le défilement manuel permet à l’utilisateur d’avoir le temps de lire le contenu à son rythme et de défiler s’il en a envie. Et en plus, c’est plus léger.

On va donc construire une simple petite zone de contenu à défilement horizontal, pour une section “Sur le même sujet” pour notre exemple. Et on va faire ça sans JS. Eh ouai, un carrousel sans JS. Quelques lignes de CSS et c’est réglé. Vous allez voir, il n’y a rien de sorcier.

D’abord l’HTML

Pour cet exemple, le balisage n’est vraiment pas foufou.

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link href="https://fonts.googleapis.com/css?family=Muli:400,800&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="normalize.min.css">
    <link rel="stylesheet" href="style.css">
    <title>CSS Snap Carousel</title>
</head>

<body>
    <header>
        <h1>Simple CSS Carousel</h1>
        <p>This carousel uses flexbox to layout content, and CSS scroll snap.</p>
        <p>It works fine on mobile and tablets too.</p>
    </header>
    <main>
        <section class="carousel">
            <ul class="carousel-items">
                <li class="carousel-item">
                    <div class="card">
                        <h2 class="card-title">My awesome article</h2>
                        <img src="https://placeimg.com/572/322/animals" />
                        <div class="card-content">
                            <p>Mewl for food at 4am chase mice. Scratch leg; meow for can opener to feed me purr when being pet nya nya nyan catasstrophe, fooled again thinking the dog likes me cough hairball on conveniently placed pants.</p>
                            <a href="#" class="button">Read more</a>
                        </div>
                    </div>
                </li>
                <li class="carousel-item">
                    <div class="card">
                        <h2 class="card-title">Just another awesome article</h2>
                        <img src="https://placeimg.com/572/322/animals" />
                        <div class="card-content">
                            <p>Mewl for food at 4am chase mice. Scratch leg; meow for can opener to feed me purr when being pet nya nya nyan catasstrophe, fooled again thinking the dog likes me cough hairball on conveniently placed pants.</p>
                            <a href="#" class="button">Read more</a>
                        </div>
                    </div>
                </li>
                <li class="carousel-item">
                    <div class="card">
                        <h2 class="card-title">Yet another awesome article</h2>
                        <img src="https://placeimg.com/572/322/animals" />
                        <div class="card-content">
                            <p>Mewl for food at 4am chase mice. Scratch leg; meow for can opener to feed me purr when being pet nya nya nyan catasstrophe, fooled again thinking the dog likes me cough hairball on conveniently placed pants.</p>
                            <a href="#" class="button">Read more</a>
                        </div>
                    </div>
                </li>
                <li class="carousel-item">
                    <div class="card">
                        <h2 class="card-title">Wow! Another awesome article</h2>
                        <img src="https://placeimg.com/572/322/animals" />
                        <div class="card-content">
                            <p>Mewl for food at 4am chase mice. Scratch leg; meow for can opener to feed me purr when being pet nya nya nyan catasstrophe, fooled again thinking the dog likes me cough hairball on conveniently placed pants.</p>
                            <a href="#" class="button">Read more</a>
                        </div>
                    </div>
                </li>
                <li class="carousel-item">
                    <div class="card">
                        <h2 class="card-title">That's some awesome article</h2>
                        <img src="https://placeimg.com/572/322/animals" />
                        <div class="card-content">
                            <p>Mewl for food at 4am chase mice. Scratch leg; meow for can opener to feed me purr when being pet nya nya nyan catasstrophe, fooled again thinking the dog likes me cough hairball on conveniently placed pants.</p>
                            <a href="#" class="button">Read more</a>
                        </div>
                    </div>
                </li>
                <li class="carousel-item">
                    <div class="card">
                        <h2 class="card-title">Just a lot or articles !</h2>
                        <img src="https://placeimg.com/572/322/animals" />
                        <div class="card-content">
                            <p>Mewl for food at 4am chase mice. Scratch leg; meow for can opener to feed me purr when being pet nya nya nyan catasstrophe, fooled again thinking the dog likes me cough hairball on conveniently placed pants.</p>
                            <a href="#" class="button">Read more</a>
                        </div>
                    </div>
                </li>
                <li class="carousel-item">
                    <div class="card">
                        <h2 class="card-title">One more, one more !</h2>
                        <img src="https://placeimg.com/572/322/animals" />
                        <div class="card-content">
                            <p>Mewl for food at 4am chase mice. Scratch leg; meow for can opener to feed me purr when being pet nya nya nyan catasstrophe, fooled again thinking the dog likes me cough hairball on conveniently placed pants.</p>
                            <a href="#" class="button">Read more</a>
                        </div>
                    </div>
                </li>
                <li class="carousel-item">
                    <div class="card">
                        <h2 class="card-title">Again !</h2>
                        <img src="https://placeimg.com/572/322/animals" />
                        <div class="card-content">
                            <p>Mewl for food at 4am chase mice. Scratch leg; meow for can opener to feed me purr when being pet nya nya nyan catasstrophe, fooled again thinking the dog likes me cough hairball on conveniently placed pants.</p>
                            <a href="#" class="button">Read more</a>
                        </div>
                    </div>
                </li>
                <li class="carousel-item">
                    <div class="card">
                        <h2 class="card-title">One last</h2>
                        <img src="https://placeimg.com/572/322/animals" />
                        <div class="card-content">
                            <p>Mewl for food at 4am chase mice. Scratch leg; meow for can opener to feed me purr when being pet nya nya nyan catasstrophe, fooled again thinking the dog likes me cough hairball on conveniently placed pants.</p>
                            <a href="#" class="button">Read more</a>
                        </div>
                    </div>
                </li>
            </ul>
        </section>
    </main>
</body>

</html>

Le carrousel est une simple <ul> et chaque item est donc un <li> qui contient une <div class="card">. Donc le balisage est ultra simple.

Sans les styles “fonctionnels”, c’est-à-dire uniquement avec quelques styles cosmétiques pour rendre tout ça moins moche, cela donne ça.

Carrousel sans JS - Etat inital
Le carrousel est une simple <ul>

Créer le défilement horizontal

Maintenant, le but du jeu est de disposer les items horizontalement, et de les faire déborder de l’écran. Pour ça, on va utiliser flexbox.

.carousel-items {
    display: flex;
    overflow-x: scroll;
    padding: 1rem 0;
}
.carousel-item {
    margin-left: 1rem;
}

Ici, on ajoute simplement display: flex; et overflow-x: scroll; sur le conteneur. J’ai aussi juste mis un peu de padding et une marge sur les items. Cela va disposer les items de gauche à droite, et faire apparaitre une barre de scroll sous le slider.

Carrousel sans JS - Avec display: flex;
Un simple display: flex; et on avance déjà bien.

Ici, le souci est que flexbox essaie de mettre tous les items sur la même ligne, et les compresse pour ce faire.

Pour corriger le tir, il faut demander à flexbox de “réserver” une place minimale à chaque item, et l’interdire de les compresser. On fait ça avec flex-basis, et flex-shrink.

.carousel-item {
    flex-grow: 1;
    flex-shrink: 0;
    flex-basis: 450px;
    margin-left: 1rem;
}

La propriété flex est un raccourci. On peut aussi écrire :

.carousel-item {
    flex: 1 0 450px;
    margin-left: 1rem;
}

Ici, on demande à flexbox que tous les items aient un rapport de taille de 1 (tous de la même taille, donc), un rapport de réduction de 0 (donc on les interdit de rétrécir) et on leur réserve 450px minimum.

Carrousel sans JS - Avec flex-basis;
flex-basis et flex-shrink permettent de dimensionner nos articles somme on veut.

Notez que la valeur de flex-basis est fixée à 450px, mais c’est uniquement pour une vue desktop. Pour les vues mobiles, il faudra mettre une valeur moindre, qui laisse entrevoir l’article suivant. Par exemple, si on prend un mobile de 375px de large, il faudra mettre une valeur pour flex-basis d’environ 250px. De cette façon, les utilisateurs sur mobile verront une partie de l’article voisin, ce qui leur suggérera un scroll horizontal. On peut aussi mettre une navigation, mais c’est pour un autre article !

Ajout du scroll snap

Nos articles défilent sans souci de gauche à droite, mais on peut améliorer tout ça, en mettant en place un petit scroll snap. C’est-à-dire qu’on va faire en sorte qu’il y ait des points d’accroche pour notre défilement, et que les articles viennent se caler proprement sur ces points lors du scroll.

C’est ultra simple. Un peu de magie CSS, c’est tout.

.carousel-items {
    display: flex;
    overflow-x: scroll;
    padding: 1rem 0;
    scroll-snap-type: x mandatory;
}

.carousel-item {
    flex: 1 0 250px;
    margin-left: 1rem;
    scroll-snap-align: start;
}

En ajoutant simplement la propriété scroll-snap-type, on va déclarer que l’on veut des points d’accroche sur le défilement et scroll-snap-align sur les items permet de déterminer où se situe le point d’accroche par item.

scroll-snap-type peut prendre plusieurs valeurs. Ici x indique que l’on veut des points d’accroche sur le défilement horizontal (y pour le vertical) et mandatory indique que le snap est obligatoire (proximity indique que le snap se fera si l’item est assez près d’un point d’accroche).

Super simple.

Il ne reste plus qu’à décorer avec une custom scroll bar, et ce sera top.

::-webkit-scrollbar-track {
    background-color: #F5F5F5;
}

::-webkit-scrollbar {
    height: 6px;
    background-color: #F5F5F5;
}

::-webkit-scrollbar-thumb {
    background-color: #3d4852;
    border-radius: 3px;
}

Et voilà ! Vous voyez ! Il est tout à fait possible de créer un simple slider ou carrousel sans JS !

Avec uniquement quelques lignes de CSS, on peut faire quelque chose de simple et fonctionnel, adapté aux mobiles et tablettes, sans charger une seule lib JS. Avec quelques lignes supplémentaires de CSS, vous pouvez faire un slider fullscreen, sur le même principe.

Pour améliorer le tout, on pourrait ajouter une navigation, adoucir le scroll, etc… A vous de jouer ! Voilà un petit pen, si vous voulez vous amuser avec le code.

Enjoy !

See the Pen Simple CSS Snap Carousel by Vincent Dubroeucq (@vincedubroeucq) on CodePen.

PS: Si vous avez aimé ce article et êtes intéressé pour apprendre à développer pour WordPress en utilisant les meilleures pratiques, jetez-un oeil à WPCookBook ! C’est un vrai livre de recettes WordPress pour apprendre à développer pour WordPress proprement et exploiter au maximum tous les outils et APIs mis à notre disposition. Inscrivez-vous pour être notifié de sa publication !

6 commentaires sur “Créer un slider ou carrousel sans JS avec CSS scroll-snap

  • Mor NDIAYE

    J’ai vraiment aimé le tuto. Il est simple et concis.
    Vincent explique bien et succinctement tout chaque ligne de code.

    Merci Vincent pour ce super tuto.

    • Vincent

      Merci ! Cool si c’était utile !

  • Thomas

    Merci beaucoup pour ce tuto !
    Je songe à ajouter des boutons de contrôle avec flèches précédentes et suivantes. Comment créer une propriété CSS pour faire un scroll via ces boutons de contrôles cités ci-haut ?
    Je vous remercie par avance de votre réponse

    • Vincent

      Là, je pense qu’il faudra ajouter du JS. Peut⁻être que de simples liens vers des ancres #slide-1, #slide-2, etc… pourraient fonctionner. Je ne sais pas, je n’ai pas testé !

  • aziz

    fantastic j’ai cherché autant de fois un exemple comme ceci sans js .. ça fonctionne parfaitement .. merci

    • Vincent

      Merci à toi !

Les commentaires sont fermés.