Bootstrap 4 : le Scrollspy

image_pdfimage_print

Ce plugin permet de relier automatiquement des éléments de navigation avec des zones HTML en utilisant un défilement. Pour information “spy” signifie espionnage, autrement dit on va espionner le défilement de la page pour le synchroniser avec la navigation.

Le principe

Pour faire fonctionner ce plugin il faut :

  • une navigation avec le composant nav (ou une liste groupée),
  • une zone à espionner (spying) qui doit comporter l’attribut data-spy=”scroll”.

D’autre part il faut relier la navigation et l’élément à espionner, dans celui-ci on utilise l’attribut data-target pour pointer la navigation.

Il faut aussi relier chaque élément de la navigation à son correspondant dans la zone à espionner, mais ça ce n’est pas particulier au plugin.

Ce qui peut ainsi se schématiser :

Un exemple simple

Pour illustrer ce fonctionnement prenons un exemple simple :

<style>
  #content {
    height: 80px;
    overflow-y: auto;
    position: relative;
  }
</style>  

...

<nav id="nav" class="navbar navbar-light bg-light">
  <ul class="nav nav-pills">
    <li class="nav-item">
      <a class="nav-link active" href="#un">un</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#deux">deux</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#trois">trois</a>
    </li>
  </ul>
</nav>
<div id="content" data-target="#nav" data-spy="scroll" data-offset="0">
  <p id="un">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  <p id="deux">Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  <p id="trois">Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p>
</div>

J’ai prévu un peu de style pour le contenu pour limiter la hauteur et avoir une barre de défilement. D’autre part il faut absolument une position relative.

Tester en ligne

Lorsqu’on fait défiler le texte on active l’item correspondant à l’identifiant de la partie de texte visible.

Mise en page

Ce plugin est essentiellement utilisé pour les mises en page de sites avec une barre de navigation et plusieurs zones à afficher, une stratégie de plus en plus utilisée. Comme un exemple est plus efficace qu’une explication, surtout pour ce genre de fonctionnement, en voici un :

<!DOCTYPE HTML>
<html>

  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link href="css/bootstrap.css" rel="stylesheet">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
    <style>
      body {
        position: relative;
        padding-top: 50px;
      }
    </style>  
  </head>

  <body data-target=".navbar-nav" data-spy="scroll" data-offset="50">

  <nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark">
    <a class="navbar-brand" href="#accueil">La boutique en délire</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".collapse">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse">      
      <ul class="navbar-nav mr-auto">
        <li class="nav-item">
          <a class="nav-link" href="#accueil">Accueil</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#produits">Produits</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#nouvelles">Nouvelles</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#localisation">Localisation</a>
        </li>
      </ul>
    </div>
  </nav>

  <section id="accueil" class="bg-primary text-center text-white py-3">
    <div class="container">
      <h1 class="py-md-2">Bienvenue dans notre espace !</h1>
      <p>"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"
      </p>
    </div>
  </section>

  <section id="produits" class="bg-dark text-center text-white py-3">
    <div class="container">
      <h1 class="py-md-2">Nos produits attractifs !</h1>
      <p>"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"
      </p>
      <hr>
      <div class="row">
        <div class="col-md-4 my-1">
          <button type="button" class="btn btn-light btn-block">
            <span class="fa fa-gavel fa-3x"></span>
            <h3 class="pt-1">Outillage</h3>
          </button>
        </div>
        <div class="col-md-4 my-1">
          <button type="button" class="btn btn-light btn-block">
            <span class="fa fa-fire fa-3x"></span>
            <h3 class="pt-1">Incendie</h3>
          </button>
        </div>
        <div class="col-md-4 my-1">
          <button type="button" class="btn btn-light btn-block">
            <span class="fa fa-home fa-3x"></span>
            <h3 class="pt-1">Habitation</h3>
          </button>
        </div>
      </div>
      <hr>
  </section>

  <section id="nouvelles" class="bg-primary text-center text-white py-3">
    <div class="container">
      <h1 class="py-md-2">Les nouvelles de nos activités !</h1>
      <p>"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"
      </p>
      <hr>
      <div class="row">
        <div class="col-md-4 my-1">
          <button type="button" class="btn btn-light btn-block">
            <span class="fa fa-headphones fa-3x"></span>
            <h3 class="pt-1">Sonorisation</h3>
          </button>
        </div>
        <div class="col-md-4 my-1">
          <button type="button" class="btn btn-light btn-block">
            <span class="fa fa-globe fa-3x"></span>
            <h3 class="pt-1">Voyage</h3>
          </button>
        </div>
        <div class="col-md-4 my-1">
          <button type="button" class="btn btn-light btn-block">
            <span class="fa fa-ship fa-3x"></span>
            <h3 class="pt-1">Transport</h3>
          </button>
        </div>
      </div>
      <hr>
    </div>
  </section>

  <section id="localisation" class="bg-dark text-center text-white py-3">
    <div class="container">
      <h1 class="py-md-2">L'emplacement de nos boutiques !</h1>
      <p>"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"
      </p>
      <hr>
      <div class="row">
        <div class="col-md-4 my-1">
          <button type="button" class="btn btn-light btn-block">
            <span class="fa fa-road fa-3x"></span>
            <h3 class="pt-1">Routes</h3>
          </button>
        </div>
        <div class="col-md-4 my-1">
          <button type="button" class="btn btn-light btn-block">
            <span class="fa fa-cutlery fa-3x"></span>
            <h3 class="pt-1">Restaurants</h3>
          </button>
        </div>
        <div class="col-md-4 my-1">
          <button type="button" class="btn btn-light btn-block">
            <span class="fa fa-television fa-3x"></span>
            <h3 class="pt-1">Télévision</h3>
          </button>
        </div>
      </div>
      <hr>
    </div>
  </section>

  <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
  <script src="js/bootstrap.js"></script>
  </body>
</html>

Tester en ligne

Lorsqu’on fait défiler la page l’item du menu correspondant à la zone affichée s’active :

Un mouvement fluide

L’exemple fonctionne correctement, mais on peut regretter la brutalité du mouvement lorsqu’on utilise le menu. La zone demandée s’affiche spontanément et on ne comprend pas vraiment qu’il se produit un défilement. Il serait plus élégant d’avoir un mouvement fluide pour passer d’une zone à une autre. Ce n’est pas prévu au niveau du plugin, mais avec quelques lignes de Javascript on peut réaliser cela :

$('a.navbar-brand, a.nav-link').on('click', function(e) {
  e.preventDefault()
  $('html, body').animate({
    scrollTop: $(this.hash).offset().top - 60
  }, 1000)
})

Tester en ligne

Activation par Javascript

On a vu dans les exemples que le plugin peut être simplement mis en œuvre avec des attributs :

<body data-target=".nav" data-spy="scroll">

Il est aussi possible de le faire avec Javascript. Pour tester cette possibilité, il faut retirer ces attributs et ajouter cette ligne de code :

$('body').scrollspy({ target: '.nav' });

Vous disposez aussi de l’événement activate.bs.scrollspy qui est déclenché lorsqu’une nouvelle zone est affichée. L’utilité de cet événement ne saute pas aux yeux, mais si vous en avez éventuellement besoin la syntaxe est la suivante :

$('#monScrollspy').on('activate.bs.scrollspy', function () {
  // Action
})

Un souci peut se présenter si vous modifiez dynamiquement le menu au niveau du DOM parce que le plugin ne sera pas au courant de ces changements. dans ce cas il faut commander un rafraîchissement :

$('[data-spy="scroll"]').each(function () {
  var $spy = $(this).scrollspy('refresh')
})

En résumé

  • Le Scrollspy permet de relier automatiquement des éléments de navigation avec des zones HTML en utilisant un défilement.
  • C’est un effet de plus en plus utilisé sur les sites web.

 

Laisser un commentaire