Comment définir le décalage pour ScrollSpy dans Bootstrap?


98

J'ai un site avec la barre de navigation fixée en haut et 3 divs en dessous dans la zone de contenu principale.

J'essaye d'utiliser scrollspy à partir du framework bootstrap.

Je l'ai mis en évidence avec succès les différents en-têtes dans le menu lorsque vous faites défiler les divs.

Je l'ai aussi, donc lorsque vous cliquez sur le menu, il défilera jusqu'à la bonne partie de la page. Cependant, le décalage est incorrect (il ne prend pas en compte la barre de navigation, je dois donc décaler d'environ 40 pixels)

Je vois sur la page Bootstrap qu'il mentionne une option de décalage mais je ne sais pas comment l'utiliser.

Je ne suis pas non plus ce que cela signifie quand il dit que vous pouvez utiliser scrollspy avec $('#navbar').scrollspy(), je ne sais pas où l'inclure, donc je ne l'ai pas fait et tout semble fonctionner (sauf le décalage).

Je pensais que le décalage pourrait être le data-offset='10'sur l'étiquette du corps, mais cela ne fait rien pour moi.

J'ai le sentiment que c'est quelque chose de vraiment évident et ça me manque. De l'aide?

Mon code est

...
<!-- note: the data-offset doesn't do anything for me -->
<body data-spy="scroll" data-offset="20">
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
    <div class="container">
    <a class="brand" href="#">VIPS</a>
    <ul class="nav">
        <li class="active">
             <a href="#trafficContainer">Traffic</a>
        </li>
        <li class="">
        <a href="#responseContainer">Response Times</a>
        </li>
        <li class="">
        <a href="#cpuContainer">CPU</a>
        </li>
      </ul>
    </div>
</div>
</div>
<div class="container">
<div class="row">
    <div class="span12">
    <div id="trafficContainer" class="graph" style="position: relative;">
    <!-- graph goes here -->
    </div>
    </div>
</div>
<div class="row">
    <div class="span12">
    <div id="responseContainer" class="graph" style="position: relative;">
    <!-- graph goes here -->
    </div>
    </div>
</div>
<div class="row">
    <div class="span12">
    <div id="cpuContainer" class="graph" style="position: relative;">
    <!-- graph goes here -->
    </div>
    </div>
</div>
</div>

...
<script src="assets/js/jquery-1.7.1.min.js"></script>
<script src="assets/js/bootstrap-scrollspy.js"></script>
</body>
</html>

Pourquoi donnez-vous une position: par rapport à vos divs? C'est peut-être ce qui cause cela. Pouvez-vous créer un jsfiddle avec votre code pour que nous puissions voir en action?
periklis

Réponses:


113

Bootstrap utilise le décalage pour résoudre uniquement l'espionnage, pas le défilement. Cela signifie que le défilement vers le bon endroit dépend de vous.

Essayez ceci, cela fonctionne pour moi: ajoutez un gestionnaire d'événements pour les clics de navigation.

var offset = 80;

$('.navbar li a').click(function(event) {
    event.preventDefault();
    $($(this).attr('href'))[0].scrollIntoView();
    scrollBy(0, -offset);
});

Je l'ai trouvé ici: https://github.com/twitter/bootstrap/issues/3316


3
Merci d'avoir répondu. Il m'a fallu un certain temps pour réaliser que le décalage n'affecte pas le défilement. Cela signifie que toute personne utilisant un toit fixe doit effectuer un réglage manuel de cette manière.
Brian Smith

8
Pour mettre à jour la section de hachage de l'URL de manière appropriée, ajoutez window.location.hash = $(this).attr('href')à cette fonction.
Stephen M. Harris

2
Merci! FWIW, mettre le décalage des données dans le corps est également important, car le demandeur dit qu'il ne fait rien, mais qu'il est nécessaire pour un espionnage approprié. Il pourrait être utile d’avoir une réponse complète.
mrooney

4
Victoire dynamique: var navOffset = $('#navbar').height();etscrollBy(0, -navOffset);
ahnbizcad

78

L'astuce, comme Tim l'a fait allusion, est de profiter du rembourrage. Le problème est que votre navigateur veut toujours faire défiler votre ancre vers le haut exact de la fenêtre. si vous définissez votre ancre là où votre texte commence réellement, il sera masqué par votre barre de menus. Au lieu de cela, vous définissez votre ancre sur l' ID du conteneur <section>ou de la <div>balise, que la nav / navbar utilisera automatiquement. Ensuite, vous devez définir votre padding-toppour le conteneur sur le montant de compensation souhaité, et le margin-toppour le conteneur sur l' opposé de padding-top. Maintenant, le bloc de votre conteneur et l'ancre commencent exactement en haut de la page, mais le contenu à l'intérieur ne commence que sous la barre de menus.

Si vous utilisez des ancres régulières, vous pouvez accomplir la même chose en utilisant une marge négative en haut dans votre conteneur comme ci-dessus, mais pas de remplissage. Ensuite, vous mettez une <a target="...">ancre régulière en tant que premier enfant du conteneur. Ensuite, vous stylisez le deuxième élément enfant avec un élément opposé mais égal margin-top, mais en utilisant le sélecteur .container:first-child +.

Tout cela suppose que votre <body>balise a déjà sa marge définie pour commencer sous votre en-tête, ce qui est la norme (sinon, la page serait rendue avec du texte occlus dès le départ).

Voici un exemple de cela en action. Tout ce qui a un identifiant sur votre page peut être lié en plaçant # the-elements-id à la fin de votre URL. Si vous créez toutes vos balises h, ajoutez des balises dt avec des identifiants pouvant être liés ( comme le fait github ) avec une sorte de script qui injecte un petit lien à leur gauche ; l'ajout de ce qui suit à votre CSS prendra en charge le décalage de la barre de navigation pour vous:

body {
    margin-top: 40px;/* make room for the nav bar */
}

/* make room for the nav bar */
h1[id],
h2[id],
h3[id],
h4[id],
h5[id],
h6[id],
dt[id]{
    padding-top: 60px;
    margin-top: -40px;
}

9
J'adore le combo padding-haut, marge négative-bas (sur le même élément). Plus facile que de déconner avec les js.
Eystein

Cela semble être la meilleure réponse, mais je suis un peu perdu. Toute chance d'un exemple.
eddyparkinson

@eddyparkinson, je suppose que vous l'avez compris maintenant: Exemple, lorsque vous avez vos identifiants sur les lignes de bootstrap: .row [id] {padding-top: 60px; margin-top: -40px; } Mettez ceci dans votre fichier less: .row [id] {padding-top: 60px; margin-top: -40px; }
Klaaz

Le paramètre de décalage par défaut du bootstrap n'est-il pas censé être pour cela? Cela ressemble à une chose si évidente à inclure et à ne pas avoir à recourir à des solutions de contournement comme celle-ci.
ahnbizcad

Cela ajoute-t-il effectivement de l'espace supplémentaire sur la div que vous ciblez? Et si tu ne veux pas ça? Un espacement supplémentaire invisible serait idéal.
ahnbizcad

10

Vous pouvez modifier le décalage de scrollspy à la volée avec ceci (en supposant que vous espionniez le corps):

offsetValue = 40;
$('body').data().scrollspy.options.offset = offsetValue;
// force scrollspy to recalculate the offsets to your targets
$('body').data().scrollspy.process();

Cela fonctionne également si vous devez modifier la valeur de décalage de manière dynamique. (J'aime que scrollspy bascule lorsque la section suivante est à peu près à mi-hauteur de la fenêtre, je dois donc changer le décalage pendant le redimensionnement de la fenêtre.)


2
Merci pour cela - fonctionne très bien avec un petit ajustement pour Bootstrap 3.0 $ ('body'). Data () ['bs.scrollspy']. Options.offset = newOffset; // Définit le nouveau décalage $ ('body'). Data () ['bs.scrollspy']. Process (); // Force scrollspy à recalculer les décalages par rapport à vos cibles $ ('body'). Scrollspy ('refresh'); // Rafraîchit le scrollspy.
Sam

J'ai trouvé que cette méthode est bonne, mais que si je veux l'utiliser pour définir le décalage depuis le début en raison de différentes hauteurs de menu, $ ('body'). Data (). Scrollspy.options.offset (ou la variante pour la version 3.0) n'est pas encore définie. Y a-t-il quelque chose d'asynchrone à propos de scrollspy qui me manque?
ness-EE

Depuis Bootstrap 3.1.1, cela devrait être $('body').data()['bs.scrollspy'].options.offset. Utile pour déclencher scrollspy lors du chargement de la page en utilisantwindow.scrollBy(X,Y)
Meredith

8

Si vous voulez un décalage de 10, vous mettriez ceci dans votre tête:

<script>
  $('#navbar').scrollspy({
    offset: 10
  });
</script>

Votre balise corporelle ressemblerait à ceci:

<body data-spy="scroll">

6
Cela ne compense pas le contenu, cela compense la navigation.
markus

Cela fonctionnera pour mettre en évidence l'élément de navigation correct et non l'emplacement où le clic mène (qui est la question d'origine des affiches). Cela dit, c'est ce que je cherchais! Merci!
valin077

6

À partir du numéro 3316 de bootstrap :

[Ceci] est uniquement destiné à modifier les calculs de défilement - nous ne décalons pas le clic d'ancrage réel

Ainsi, la définition du décalage n'affecte que l' endroit où scrollspy pense que la page est défilée . Cela n'affecte pas le défilement lorsque vous cliquez sur une balise d'ancrage.

L'utilisation d'une barre de navigation fixe signifie que le navigateur fait défiler jusqu'au mauvais endroit. Vous pouvez résoudre ce problème avec JavaScript:

var navOffset = $('.navbar').height();

$('.navbar li a').click(function(event) {
    var href = $(this).attr('href');

    // Don't let the browser scroll, but still update the current address
    // in the browser.
    event.preventDefault();
    window.location.hash = href;

    // Explicitly scroll to where the browser thinks the element
    // is, but apply the offset.
    $(href)[0].scrollIntoView();
    window.scrollBy(0, -navOffset);
});

Cependant, pour vous assurer que scrollspy met en évidence l'élément courant correct, vous devez toujours définir le décalage:

<body class="container" data-spy="scroll" data-target=".navbar" data-offset="70">

Voici une démo complète sur JSFiddle .


Alternativement, vous pouvez compléter vos balises d'ancrage, comme suggéré par les astuces CSS .

a[id]:before { 
  display: block; 
  content: " ";
  // Use the browser inspector to find out the correct value here.
  margin-top: -285px; 
  height: 285px; 
  visibility: hidden; 
}

1

Je pense que ce décalage pourrait faire quelque chose avec la position inférieure de la section.

J'ai résolu mon problème - le même que le vôtre - en ajoutant

  padding-top: 60px;

dans la section déclaration pour dans bootstrap.css

J'espère que cela pourra aider!


qu'est-ce qu'une "déclaration pour la section" Où mettez-vous ce code?
ahnbizcad

1

J'ai ajouté un .vspaceélément de 40 px de hauteur tenant l'ancre avant chacun de mes h1éléments.

<div class="vspace" id="gherkin"></div>
<div class="page-header">
  <h1>Gherkin</h1>
</div>

Dans le CSS:

.vspace { height: 40px;}

Cela fonctionne très bien et l'espace n'est pas étouffant.


1

Bootstrap 4 (mise à jour 2019)

Mise en œuvre: navigation fixe, Scrollspy et défilement fluide

C'est la solution de @ wilfred-hughes ci-dessus, c'est exactement corrige le problème de chevauchement avec la barre de navigation fixe Bootstrap en utilisant CSS ':: before' pour ajouter un bloc non affiché avant chaque balise de section. Avantage: vous ne vous retrouvez pas avec un rembourrage inutile entre vos sections. Par exemple, la section 3 peut être positionnée verticalement contre la section 2 et elle défilera toujours jusqu'à la position exacte exacte en haut de la section 3.

Remarque latérale: la définition du décalage de scrollspy dans la balise de script ne provoquait rien ($ ('# navbar'). Scrollspy ({offset: 105});) et les tentatives d'ajustement du décalage dans le bloc d'animation entraînaient toujours un désalignement post- animation.

index.html

<section id="section1" class="my-5">
...
<section id="section2" class="my-5">
...
<section id="section3" class="my-5">
...

plus tard dans index.html ...

 <script>
      // Init Scrollspy
      $('body').scrollspy({ target: '#main-nav' });

      // Smooth Scrolling
      $('#main-nav a').on('click', function(event) {
        if (this.hash !== '') {
          event.preventDefault();

          const hash = this.hash;

          $('html, body').animate(
            {
              scrollTop: $(hash).offset().top
            },
            800,
            function() {
              window.location.hash = hash;
            }
          );
        }
      });
    </script>

style.css:

// Solution to Fixed NavBar overlapping content of the section.  Apply to each navigable section.
// adjust the px values to your navbar height
// Source: https://github.com/twbs/bootstrap/issues/1768
#section1::before,
#section2::before,
#section3::before {
  display: block;
  content: ' ';
  margin-top: -105px;
  height: 105px;
  visibility: hidden;
}

body {
  padding-top: 105px;
}

Crédit: @ wilfred-hughes ci-dessus et la source originale de l'utilisateur @mnot à https://github.com/twbs/bootstrap/issues/1768


1
Merci! ugh j'ai lutté avec ça pendant une heure, LOL!
Nexus

0

J'ai eu des problèmes avec les solutions d'acjohnson55 et Kurt UXD. Les deux fonctionnaient pour cliquer sur un lien vers le hachage, mais le décalage de scrollspy n'était toujours pas correct.

J'ai trouvé la solution suivante:

<div class="anchor-outer">
  <div id="anchor">
    <div class="anchor-inner">
      <!-- your content -->
    </div>
  </div>
</div>

Et le CSS correspondant:

body {
  padding-top:40px;
}

.anchor-outer {
  margin-top:-40px;
}

.anchor-inner {
  padding-top:40px;
}

@media (max-width: 979px) {
  body {
    padding-top:0px;
  }

  .anchor-outer {
    margin-top:0px;
  }

  .anchor-inner {
    padding-top:0px;
  }
}

@media (max-width: 767px) {
  body {
    padding-top:0px;
  }

  .anchor-outer {
    margin-top:0px;
  }

  .anchor-inner {
    padding-top:0px;
  }
}

Vous devrez remplacer le remplissage / marge de 40px par la hauteur de votre barre de navigation et l'ID de votre ancre.

Dans cette configuration, je peux même observer un effet de la définition d'une valeur pour l'attribut data-offset. Si trouver de grandes valeurs pour le décalage de données autour de 100-200 conduisent à un comportement plus attendu (le scrollspy- "switch" se produira si l'en-tête est à peu près au milieu de l'écran).

J'ai également trouvé que scrollspy est très sensible aux erreurs comme les balises div non fermées (ce qui est assez évident), donc http://validator.w3.org/check était mon ami ici.

À mon avis, scrollspy fonctionne mieux avec des sections entières portant l'ID d'ancrage, car les éléments d'ancrage normaux ne conduisent pas aux effets attendus lors du défilement vers l'arrière (le scrollspy- "switch" se produit finalement dès que vous appuyez sur l'élément d'ancrage, par exemple votre titre, mais à ce moment-là, vous avez déjà fait défiler le contenu dont l'utilisateur s'attend à ce qu'il appartienne à l'en-tête correspondant).


0

Si vous êtes tombé sur cette question (comme je l'ai fait) via Google et que vous cherchez toujours un moyen de modifier dynamiquement le décalage de scrollspy. J'attache maintenant un lien vers une solution qui a fonctionné pour moi.

Jetez un œil à ce post que j'ai fait dans un autre fil . Il contient un extrait de code sur la façon dont vous pouvez modifier par programmation la valeur de décalage et réagir dynamiquement aux changements (par exemple si la barre de navigation change de taille).

Vous n'avez pas besoin de bricoler avec des correctifs CSS, mais plutôt de définir le décalage dont vous avez actuellement besoin en fonction de certains événements.


-1

Vous pouvez également ouvrir bootstap-offset.jset modifier

$.fn.scrollspy.defaults = {
  offset: 10
}

Là.


1
Le décalage scrollspy ne décale pas le contenu, il décale la navigation.
markus

-1

Il suffit de régler:

data-offset="200"

data-offsetest par défaut "50" et cela équivaut à 10px, alors augmentez simplement data-offsetet votre problème est résolu.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.