Pagination (Pagination)

La pagination aide les utilisateurs à naviguer dans de grandes quantités de pages, en offrant aux utilisateurs et aux moteurs de recherche (SEO) un système de navigation donnant accès à toutes les pages. Ce nombre de pages pouvant être très important, il faut proposer un système de navigation qui permet d’aller sur n’importe quelle page en un minimum de liens.

Usage

  • L’utilisateur consulte un grand nombre d’éléments répartis sur plusieurs pages.
  • La pagination indique à l’utilisateur où il se trouve parmi ces pages.
  • Certaines pages ont un accès direct, contrairement à d’autres.
  • L’ensemble de la pagination est composé de la première page, la page précédente, la page courante, la page suivante et la dernière page. Une liste de pages est accessible le cas échéant sur la page courante.

Page courante

  • La position actuelle est toujours mise en évidence afin que l’utilisateur puisse se repérer dans l’ensemble de la pagination.
  • Quand le composant pagination est inactif (pas de navigation possible), la page courante n’a pas de rendu inactif pour que le numéro de page reste visible.

Liste des pages

  • Une tape sur l’ensemble de l’élément page courante permet d’afficher une liste de pages.
  • Elle est composée de certains numéros de pages :
    • Toutes les unités de la dizaine en cours. - Les dizaines suivantes jusqu’à la centaine suivante exclue.
    • Les centaines suivantes jusqu’au millier suivant exclue.
    • Les milliers suivants.

Page suivante

  • La page suivante est toujours située avant la dernière page.
  • L’accès à la page suivante est désactivé lorsque la page courante est la dernière.

Dernière page

  • La dernière page est toujours le dernier élément graphique de la pagination.
  • L’accès à la dernière page est désactivé lorsque la page courante est la dernière.

Page précédente

  • La page précédente est toujours le deuxième élément de la pagination.
  • L’accès à la page précédente est désactivé lorsque la page courante est la première.

Première page

  • La première page est toujours le premier élément graphique de la pagination.
  • L’accès à la première page est désactivé lorsque la page courante est la première.

Bonnes pratiques

  • L’ensemble de la pagination se trouve après les données.
  • La pagination est centrée dans son parent.
  • Chaque page contient la même quantité de données, à l’exception de la dernière page.
  • Le nombre d’éléments dans une page est défini en fonction des tailles des pages, des données et de leur temps de chargement.

Style & code

Dépendances :

Toute la complexité de ce composant est dans la construction des listes de liens. Pour des raisons techniques évidentes, cette construction est à faire au niveau de la page et non du composant. Elle ne peut donc être portée par SipaUI. De fait, ce composant n’intègre pas d’intelligence, il s’agit juste de HTML et de CSS. La construction vous incombe donc et dépendra de la technologie que vous utilisez (PHP, Twig, JS, JSP…).

Principe général

La pagination est composée d’une balise <nav> (puisqu’il s’agit d’un système de navigation) contenant 2 listes imbriquées (<ul> et <li>), et de 2 boutons d’ouverture et fermeture de la liste de pages (<button type="button">). La première liste contient les éléments de navigation de premier niveau (page 1, précédente, page en cours, suivante et dernière page). La seconde liste contient les accès vers les autres pages. Le bouton sous ces listes permet de simplifier la fermeture de la liste de pages en permettant le clic à l’extérieur de cette liste.

Architecture de base :

<nav>
    <ul>
        <li>1</li>
        <li>précédent</li>
        <li>
            <button type="button">1</button>
            <ul>
                <li>1</li>
                <li>2</li>
                <li>3</li>
                <li>4</li>
                <li>5</li>
                <li>6</li>
                <li>…</li>
            </ul>
        </li>
        <li>suivant</li>
        <li>100</li>
    </ul>
    <button type="button">Fermer la liste de pages</button>
</nav>

Construction concrète

Plusieurs classes sont nécessaires pour donner l’apparence voulue à ce code HTML. Cf. les explications ci-après pour en avoir le détail.

Exemple de code complet :

<nav class="su-pagination su-first-page" aria-label="Pagination de la liste d’articles">
    <ul>
        <li><span>1</span></li>
        <li><span><i class="su-icon">précédent</i></span></li>
        <li class="su-page-select">
            <button type="button" aria-label="Afficher la liste de pages" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in"}'><span class="su-visually-hidden">Page en cours :</span>1</button>
            <ul class="su-pages-list">
                <li class="su-page-active">1</li>
                <li><a href="javascript:;">2</a></li>
                <li><a href="javascript:;">3</a></li>
                <li><a href="javascript:;">4</a></li>
                <li><a href="javascript:;">5</a></li>
                <li><a href="javascript:;">6</a></li>
                <li><a href="javascript:;">7</a></li>
                <li><a href="javascript:;">8</a></li>
                <li class="su-separator"><a href="javascript:;">9</a></li>
                <li><a href="javascript:;">10</a></li>
                <li><a href="javascript:;">20</a></li>
                <li><a href="javascript:;">30</a></li>
            </ul>
        </li>
        <li><a href="javascript:;"><i class="su-icon">suivant</i></a></li>
        <li><a href="javascript:;">30</a></li>
    </ul>
    <button type="button" class="su-close" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in","force":0}'>Fermer la liste de pages</button>
</nav>

Explications

La classe su-pagination sur <nav> est la classe d’identification du composant. Sur cette même balise peuvent être ajoutées les classes su-first-page et su-last-page quand l’utilisateur est sur la première, la dernière page ou qu’il n’y a qu’une page. Cela permet de rendre les 2 premiers ou les 2 derniers « boutons », ainsi que le sélecteur de page, visuellement inactifs en fonction des cas (cf. plus bas).

La navigation de base comporte les liens vers la première page, la page précédente, le bouton d’accès à la liste de pages, la page suivante et la dernière page. Les boutons pour la page précédente et la page suivante utilisent la fonte d’icônes pour afficher les chevrons grâce à la classe su-icon.

su-page-select identifie la zone qui contient le bouton d’affichage de la liste des pages proposées et cette liste. Sur le bouton, on utilise un data-sutoggleclass pour afficher / masquer la liste grâce à la classe su-pages-list-in. Aucun paramètre particulier à changer dans cet attribut. Par ailleurs, le bouton comporte un aria-label pour l’accessibilité, ainsi qu’un <span class="su-visually-hidden"> contenant un texte explicatif, aussi pour l’accessibilité, suivi du numéro de la page en cours.

La classe su-pages-list est pour la liste proprement dite. Pour construire la liste, se référer à la partie « Variations en fonction de la position dans le nombre de pages » ci-dessous. Dans cette liste, vous devez positionner la classe su-page-active pour identifier la page en cours de lecture et supprimer le lien sur cette page et enfin ajouter la classe su-separator sur les pages de fin de zone logique (cf. plus bas).

Enfin, sous cette navigation, se trouve un bouton pour faciliter la fermeture du volet de liste de pages. Ce bouton (qui fait toute la taille de la page, mais est invisible) possède la classe su-close et un data-sutoggleclass qu’il n’est pas nécessaire de modifier.

Variations en fonction du nombre de pages totales

Cas avec 1 page

S’il n’y a qu’une page, les boutons de navigations et la liste de pages sont inutiles. Ils sont donc désactivés. Pour cela, par rapport au code standard, il faut ajouter les classes su-first-page su-last-page sur le composant, enlever le JS d’affichage de la liste, la liste et le bouton de fermeture de la liste, remplacer les liens <a> par des <span> et ajouter disabled sur le bouton.

<nav class="su-pagination su-first-page su-last-page" aria-label="Pagination de la liste d’articles">
        <ul>
            <li><span>1</span></li>
            <li><span><i class="su-icon">précédent</i></span></li>
            <li class="su-page-select">
                <button type="button" disabled><span class="su-visually-hidden">Page en cours :</span>1</button>
            </li>
            <li><span><i class="su-icon">suivant</i></span></li>
            <li><span>1</span></li>
        </ul>
</nav>

N. B. – Bien que non souhaitable (notamment pour des questions de SEO), le composant permet de s’affranchir de l’obligation de passer les liens <a> en <span> s’il y a impossibilité technique. Dans ce cas, il faudrait quand même ajouter l’attribut aria-disabled="true" sur les <a> inactifs pour rendre ces liens inactifs aussi pour les navigateurs textes, vocaux…

Cas avec 7 pages

Quand il y a un faible nombre de pages (inférieur au nombre maximum de pages affichables dans le volet ouvert), il n’y a pas de scroll ni de dégradé indiquant qu’il y a une suite en bas de liste.

<nav class="su-pagination su-first-page" aria-label="Pagination de la liste d’articles">
    <ul>
        <li><span>1</span></li>
        <li><span><i class="su-icon">précédent</i></span></li>
        <li class="su-page-select">
            <button type="button" aria-label="Afficher la liste de pages" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in"}'><span class="su-visually-hidden">Page en cours :</span>1</button>
            <ul class="su-pages-list">
                <li class="su-page-active">1</li>
                <li><a href="javascript:;">2</a></li>
                <li><a href="javascript:;">3</a></li>
                <li><a href="javascript:;">4</a></li>
                <li><a href="javascript:;">5</a></li>
                <li><a href="javascript:;">6</a></li>
                <li><a href="javascript:;">7</a></li>
            </ul>
        </li>
        <li><a href="javascript:;"><i class="su-icon">suivant</i></a></li>
        <li><a href="javascript:;">7</a></li>
    </ul>
    <button type="button" class="su-close" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in","force":0}'>Fermer la liste de pages</button>
</nav>
Cas avec 56 pages

Avec un nombre de pages supérieur à la capacité d’affichage du volet, le scroll et le dégradé sont apparus.

<nav class="su-pagination su-first-page" aria-label="Pagination de la liste d’articles">
    <ul>
        <li><span>1</span></li>
        <li><span><i class="su-icon">précédent</i></span></li>
        <li class="su-page-select">
            <button type="button" aria-label="Afficher la liste de pages" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in"}'><span class="su-visually-hidden">Page en cours :</span>1</button>
            <ul class="su-pages-list">
                <li class="su-page-active">1</li>
                <li><a href="javascript:;">2</a></li>
                <li><a href="javascript:;">3</a></li>
                <li><a href="javascript:;">4</a></li>
                <li><a href="javascript:;">5</a></li>
                <li><a href="javascript:;">6</a></li>
                <li><a href="javascript:;">7</a></li>
                <li><a href="javascript:;">8</a></li>
                <li class="su-separator"><a href="javascript:;">9</a></li>
                <li><a href="javascript:;">10</a></li>
                <li><a href="javascript:;">20</a></li>
                <li><a href="javascript:;">30</a></li>
                <li><a href="javascript:;">40</a></li>
                <li><a href="javascript:;">50</a></li>
            </ul>
        </li>
        <li><a href="javascript:;"><i class="su-icon">suivant</i></a></li>
        <li><a href="javascript:;">56</a></li>
    </ul>
    <button type="button" class="su-close" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in","force":0}'>Fermer la liste de pages</button>
</nav>

Variations en fonction de la position dans le nombre de pages

La position de la page en cours de consultation détermine la construction de la liste de liens. Cette construction doit suivre ces règles :

  • On commence par lister les pages appartenant au même groupe d’unité que la page en cours (p. ex. : la page en cours est 36, on liste 30, 31, 32, 33, 34, 35, 36, 37, 38 et 39).
  • On n’affiche pas les pages précédant ce groupe.
  • On liste ensuite les dizaines qui suivent jusqu’à la centaine (p. ex. : avec le même cas que ci-dessus, 40, 50, 60, 70, 80, 90).
  • Ensuite, on continue avec la même logique avec les centaines et les milliers.
  • Enfin, on met la classe su-separator sur la dernière page de chaque catégorie, excepté la dernière.

On obtient ainsi pour la page 36 sur 2125 la liste suivante : 30, 31, 32, 33, 34, 35, 36, 37, 38 et 39, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000.

Cas en page 1 sur 2318 (première page)

Quand on est sur la 1re page, les 2 premiers « boutons » doivent être inactifs. Pour cela, comme expliqué plus haut dans la partie « Construction concrète », on ajoute la classe su-first-page sur le composant et on remplace les <a> par des <span>.

<nav class="su-pagination su-first-page" aria-label="Pagination de la liste d’articles">
    <ul>
        <li><span>1</span></li>
        <li><span><i class="su-icon">précédent</i></span></li>
        <li class="su-page-select">
            <button type="button" aria-label="Afficher la liste de pages" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in"}'><span class="su-visually-hidden">Page en cours :</span>1</button>
            <ul class="su-pages-list">
                <li class="su-page-active">1</li>
                <li><a href="javascript:;">2</a></li>
                <li><a href="javascript:;">3</a></li>
                <li><a href="javascript:;">4</a></li>
                <li><a href="javascript:;">5</a></li>
                <li><a href="javascript:;">6</a></li>
                <li><a href="javascript:;">7</a></li>
                <li><a href="javascript:;">8</a></li>
                <li class="su-separator"><a href="javascript:;">9</a></li>
                <li><a href="javascript:;">10</a></li>
                <li><a href="javascript:;">20</a></li>
                <li><a href="javascript:;">30</a></li>
                <li><a href="javascript:;">40</a></li>
                <li><a href="javascript:;">50</a></li>
                <li><a href="javascript:;">60</a></li>
                <li><a href="javascript:;">70</a></li>
                <li><a href="javascript:;">80</a></li>
                <li class="su-separator"><a href="javascript:;">90</a></li>
                <li><a href="javascript:;">100</a></li>
                <li><a href="javascript:;">200</a></li>
                <li><a href="javascript:;">300</a></li>
                <li><a href="javascript:;">400</a></li>
                <li><a href="javascript:;">500</a></li>
                <li><a href="javascript:;">600</a></li>
                <li><a href="javascript:;">700</a></li>
                <li><a href="javascript:;">800</a></li>
                <li class="su-separator"><a href="javascript:;">900</a></li>
                <li><a href="javascript:;">1000</a></li>
                <li><a href="javascript:;">2000</a></li>
            </ul>
        </li>
        <li><a href="javascript:;"><i class="su-icon">suivant</i></a></li>
        <li><a href="javascript:;">2318</a></li>
    </ul>
    <button type="button" class="su-close" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in","force":0}'>Fermer la liste de pages</button>
</nav>
Cas en page 1565 sur 2318 pages

Dans ce cas, à part la construction de la liste, rien de particulier. Ne pas oublier de mettre la classe su-page-active et de supprimer le lien sur la page en cours…

<nav class="su-pagination" aria-label="Pagination de la liste d’articles">
    <ul>
        <li><a href="javascript:;">1</a></li>
        <li><a href="javascript:;"><i class="su-icon">précédent</i></a></li>
        <li class="su-page-select">
            <button type="button" aria-label="Afficher la liste de pages" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in"}'><span class="su-visually-hidden">Page en cours :</span>1565</button>
            <ul class="su-pages-list">          
                <li><a href="javascript:;">1560</a></li>
                <li><a href="javascript:;">1561</a></li>
                <li><a href="javascript:;">1562</a></li>
                <li><a href="javascript:;">1563</a></li>
                <li><a href="javascript:;">1564</a></li>
                <li class="su-page-active">1565</li>
                <li><a href="javascript:;">1566</a></li>
                <li><a href="javascript:;">1567</a></li>
                <li><a href="javascript:;">1568</a></li>
                <li class="su-separator"><a href="javascript:;">1569</a></li>
                <li><a href="javascript:;">1570</a></li>
                <li><a href="javascript:;">1580</a></li>
                <li class="su-separator"><a href="javascript:;">1590</a></li>
                <li><a href="javascript:;">1600</a></li>
                <li><a href="javascript:;">1700</a></li>
                <li><a href="javascript:;">1800</a></li>
                <li class="su-separator"><a href="javascript:;">1900</a></li>
                <li><a href="javascript:;">2000</a></li>
            </ul>
        </li>
        <li><a href="javascript:;"><i class="su-icon">suivant</i></a></li>
        <li><a href="javascript:;">2318</a></li>
    </ul>
    <button type="button" class="su-close" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in","force":0}'>Fermer la liste de pages</button>
</nav>
Cas en page 2318 sur 2318 (dernière page)

Quand on est sur la dernière page, les 2 derniers « boutons » sont inactifs. Pour cela, on ajoute la classe su-last-page sur le composant, on remplace les <a> des 2 derniers boutons par des <span>. Le bouton d’affichage de la liste de page ne contiendra alors plus que la liste des unités de la dizaine en cours…

<nav class="su-pagination su-last-page" aria-label="Pagination de la liste d’articles">
    <ul>
        <li><a href="javascript:;">1</a></li>
        <li><a href="javascript:;"><i class="su-icon">précédent</i></a></li>
        <li class="su-page-select">
            <button type="button" aria-label="Afficher la liste de pages" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in"}'><span class="su-visually-hidden">Page en cours :</span>2318</button>
            <ul class="surcharge-storybook su-pages-list">          
                <li><a href="javascript:;">2310</a></li>
                <li><a href="javascript:;">2311</a></li>
                <li><a href="javascript:;">2312</a></li>
                <li><a href="javascript:;">2313</a></li>
                <li><a href="javascript:;">2314</a></li>
                <li><a href="javascript:;">2315</a></li>
                <li><a href="javascript:;">2316</a></li>
                <li><a href="javascript:;">2317</a></li>
                <li class="su-page-active">2318</li>
            </ul>
        </li>                       
        <li><span><i class="su-icon">suivant</i></span></li>
        <li><span>2318</span></li>
    </ul>
    <button type="button" class="su-close" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in","force":0}'>Fermer la liste de pages</button>
</nav>

Accessibilité

Pour rendre le composant pagination accessible il faut donner le rôle de cet élément (c’est à dire : la navigation) et préciser le contexte. Pour le rôle, c’est assuré par la présence de la balise <nav>. Pour le contexte, il faut utiliser l’attribut aria-label="Context à préciser".

Version sur fond sombre

Pour gérer le cas sur fond foncé, il faut ajouter à côté, ou au-dessus de la classe su-pagination la classe su-negative.

<div style="background: DimGray; padding: 10px; height: 360px;">
    <nav class="su-pagination su-first-page su-negative" aria-label="Pagination de la liste d’articles">
        <ul>
            <li><span>1</span></li>
            <li><span><i class="su-icon">précédent</i></span></li>
            <li class="su-page-select">
                <button type="button" aria-label="Afficher la liste de pages" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in"}'><span class="su-visually-hidden">Page en cours :</span>1</button>
                <ul class="su-pages-list">
                    <li class="su-page-active">1</li>
                    <li><a href="javascript:;">2</a></li>
                    <li><a href="javascript:;">3</a></li>
                    <li><a href="javascript:;">4</a></li>
                    <li><a href="javascript:;">5</a></li>
                    <li><a href="javascript:;">6</a></li>
                    <li><a href="javascript:;">7</a></li>
                    <li><a href="javascript:;">8</a></li>
                    <li class="su-separator"><a href="javascript:;">9</a></li>
                    <li><a href="javascript:;">10</a></li>
                    <li><a href="javascript:;">20</a></li>
                    <li><a href="javascript:;">30</a></li>
                </ul>
            </li>
            <li><a href="javascript:;"><i class="su-icon">suivant</i></a></li>
            <li><a href="javascript:;">30</a></li>
        </ul>
        <button type="button" class="su-close" data-sutoggleclass='{"parent":"nav","klass":"su-pages-list-in","force":0}'>Fermer la liste de pages</button>
    </nav>
</div>

Liste des classes disponibles

  • su-pagination
  • su-first-page (ajoutée dans le DOM en fonction de la page en cours)
  • su-last-page (ajoutée dans le DOM en fonction de la page en cours)
  • su-page-select
  • su-pages-list
  • su-pages-list-in (posée par le JS)
  • su-page-active
  • su-separator
  • su-close
  • su-negative

Classes annexes

Le code a bien été copié !