Wie setze ich den Offset für ScrollSpy in Bootstrap?


98

Ich habe eine Site mit der Navigationsleiste oben und 3 Divs darunter im Hauptinhaltsbereich.

Ich versuche, scrollspy aus dem Bootstrap-Framework zu verwenden.

Ich habe es erfolgreich die verschiedenen Überschriften im Menü hervorgehoben, wenn Sie über die Divs scrollen.

Ich habe es auch so, wenn Sie auf das Menü klicken, wird es zum richtigen Teil der Seite scrollen. Der Versatz ist jedoch falsch (die Navigationsleiste wird nicht berücksichtigt, daher muss ich um etwa 40 Pixel versetzen).

Ich sehe auf der Bootstrap-Seite , dass eine Offset-Option erwähnt wird, aber ich bin nicht sicher, wie ich sie verwenden soll.

Ich bin auch nicht das, was es bedeutet, wenn es heißt, dass Sie Scrollspy verwenden $('#navbar').scrollspy()können. Ich bin mir nicht sicher, wo ich es einfügen soll , also habe ich es nicht getan und alles scheint zu funktionieren (außer dem Offset).

Ich dachte, der Offset könnte der data-offset='10'auf dem Body-Tag sein, aber er tut nichts für mich.

Ich habe das Gefühl, dass dies etwas wirklich Offensichtliches ist und ich vermisse es einfach. Irgendeine Hilfe?

Mein Code ist

...
<!-- 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>

Warum gibst du eine Position: relativ zu deinen Divs? Vielleicht ist es das, was das verursacht. Können Sie mit Ihrem Code eine jsfiddle erstellen, damit wir sie in Aktion sehen können?
Periklis

Antworten:


113

Bootstrap verwendet Offset, um nur Spionage aufzulösen, nicht das Scrollen. Dies bedeutet, dass es an Ihnen liegt, zum richtigen Ort zu scrollen.

Versuchen Sie dies, es funktioniert für mich: Fügen Sie einen Ereignishandler für die Navigationsklicks hinzu.

var offset = 80;

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

Ich habe es hier gefunden: https://github.com/twitter/bootstrap/issues/3316


3
Danke für die Antwort. Es hat eine ganze Weile gedauert, bis mir klar wurde, dass der Versatz das Scrollen nicht beeinflusst. Dies bedeutet, dass jeder, der ein festes Verdeck verwendet, auf diese Weise manuell einstellen muss.
Brian Smith

8
Fügen Sie window.location.hash = $(this).attr('href')dieser Funktion hinzu , um den Hash-Abschnitt der URL entsprechend zu aktualisieren .
Stephen M. Harris

2
Vielen Dank! FWIW, das Einfügen des Datenversatzes in den Körper ist ebenfalls wichtig, da der Fragesteller sagt, dass er nichts tut, aber für eine ordnungsgemäße Spionage benötigt wird. Es könnte hilfreich sein, eine umfassende Antwort zu haben.
Mrooney

4
Dynamischer Sieg: var navOffset = $('#navbar').height();undscrollBy(0, -navOffset);
ahnbizcad

78

Der Trick besteht, wie Tim anspielte, darin, die Polsterung auszunutzen. Das Problem ist also, dass Ihr Browser Ihren Anker immer genau zum oberen Rand des Fensters scrollen möchte. Wenn Sie Ihren Anker dort setzen, wo Ihr Text tatsächlich beginnt, wird er von Ihrer Menüleiste verdeckt. Stattdessen setzen Sie Ihren Anker auf die ID des Containers <section>oder <div>Tags, die von nav / navbar automatisch verwendet wird. Dann müssen Sie Ihre padding-topfür den Container auf den gewünschten Mengenversatz und die margin-topfür den Container auf das Gegenteil von einstellen padding-top. Jetzt beginnen der Block Ihres Containers und der Anker genau oben auf der Seite, aber der Inhalt beginnt erst unterhalb der Menüleiste.

Wenn Sie normale Anker verwenden, können Sie dasselbe erreichen, indem Sie in Ihrem Container einen negativen Rand oben wie oben verwenden, jedoch keine Polsterung. Dann setzen Sie <a target="...">als erstes Kind des Containers einen regulären Anker. Dann formatieren Sie das zweite untergeordnete Element mit einem entgegengesetzten, aber gleichen Element margin-top, aber mit dem Selektor .container:first-child +.

Dies alles setzt voraus, dass <body>der Rand Ihres Tags bereits so eingestellt ist, dass er unter Ihrer Kopfzeile beginnt. Dies ist die Norm (andernfalls würde die Seite sofort mit verdecktem Text gerendert).

Hier ist ein Beispiel dafür in Aktion. Alles auf Ihrer Seite mit einer ID kann verknüpft werden, indem Sie # die-Elemente-ID an das Ende Ihrer URL anheften. Wenn Sie alle Ihre h-Tags und dt-Tags mit IDs verknüpfbar machen ( wie es Github tut ), mit einer Art Skript, das links davon einen kleinen Link einfügt ; Wenn Sie Ihrem CSS Folgendes hinzufügen, wird der Versatz der Navigationsleiste für Sie erledigt:

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
Ich mag die Kombination aus Polsterung oben, negativem Rand unten (am selben Element). Einfacher als mit dem js herumzuspielen.
Eystein

Sieht nach der besten Antwort aus, aber ich bin ein wenig verloren. Jede Chance auf ein Beispiel.
Eddyparkinson

@eddyparkinson, schätze, du hast es gerade herausgefunden: Beispiel, wenn du deine IDs in den Zeilen des Bootstraps hast: .row [id] {padding-top: 60px; Rand oben: -40px; } Fügen Sie dies in Ihre weniger Datei ein: .row [id] {padding-top: 60px; Rand oben: -40px; }
Klaaz

Soll der Standard-Offset-Parameter des Bootstraps nicht dafür sein? Es scheint so naheliegend zu sein, dies zu berücksichtigen, und muss nicht auf solche Problemumgehungen zurückgreifen.
Ahnbizcad

Fügt dies effektiv zusätzlichen Speicherplatz auf dem Div hinzu, auf das Sie abzielen? Was ist, wenn du das nicht willst? Ein unsichtbarer zusätzlicher Abstand wäre ideal.
Ahnbizcad

10

Sie können damit den Versatz von Scrollspy im laufenden Betrieb ändern (vorausgesetzt, Sie spionieren den Körper aus):

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

Dies funktioniert auch, wenn Sie den Versatzwert dynamisch ändern müssen. (Ich möchte, dass der Scrollspy umschaltet, wenn sich der nächste Abschnitt etwa auf halber Höhe des Fensters befindet, sodass ich den Versatz während der Fenstergröße ändern muss.)


2
Vielen Dank dafür - funktioniert hervorragend mit einer kleinen Anpassung für Bootstrap 3.0 $ ('body'). Data () ['bs.scrollspy']. Options.offset = newOffset; // Setze den neuen Offset $ ('body'). Data () ['bs.scrollspy']. Process (); // Scrollspy zwingen, die Offsets zu deinen Zielen neu zu berechnen $ ('body'). Scrollspy ('refresh'); // Aktualisiere den Scrollspy.
Sam

Ich habe festgestellt, dass diese Methode gut ist, aber wenn ich sie verwenden möchte, um den Versatz von Anfang an festzulegen, weil unterschiedliche Menühöhen vorhanden sind, wird $ ('body'). Data (). Scrollspy.options.offset (oder Die Variante für Version 3.0) ist noch nicht eingestellt. Gibt es etwas Asynchrones an Scrollspy, das mir fehlt?
Ness-EE

Ab Bootstrap 3.1.1 sollte dies sein $('body').data()['bs.scrollspy'].options.offset. Nützlich zum Auslösen von Scrollspy beim Laden von Seiten mitwindow.scrollBy(X,Y)
Meredith

8

Wenn Sie einen Versatz von 10 wollen, würden Sie dies in Ihren Kopf setzen:

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

Ihr Body Tag würde folgendermaßen aussehen:

<body data-spy="scroll">

6
Das gleicht den Inhalt nicht aus, sondern das Navigationsgerät.
Markus

Dies funktioniert, um das richtige Navigationselement hervorzuheben und nicht die Stelle, an die der Klick führt (dies ist die ursprüngliche Posterfrage). Nachdem dies gesagt war, war es das, wonach ich gesucht habe! Vielen Dank!
Valin077

6

Ab Bootstrap-Problem Nr. 3316 :

[Dies] dient nur zum Ändern von Bildlaufberechnungen - wir verschieben den tatsächlichen Ankerklick nicht

Das Einstellen des Versatzes wirkt sich also nur dort aus, wo Scrollspy glaubt, dass die Seite gescrollt wird . Das Scrollen wird nicht beeinflusst, wenn Sie auf ein Ankertag klicken.

Die Verwendung einer festen Navigationsleiste bedeutet, dass der Browser an die falsche Stelle blättert. Sie können dies mit JavaScript beheben:

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);
});

Um sicherzustellen, dass scrollspy das richtige aktuelle Element hervorhebt, müssen Sie dennoch den Versatz festlegen:

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

Hier ist eine vollständige Demo zu JSFiddle .


Alternativ können Sie Ihre Ankertags auffüllen, wie dies durch CSS-Tricks vorgeschlagen wird .

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

Ich denke, dass der Versatz etwas mit der unteren Position des Abschnitts zu tun haben könnte.

Ich habe mein Problem - genau wie Ihres - durch Hinzufügen behoben

  padding-top: 60px;

in der Deklaration für Abschnitt in bootstrap.css

Hoffentlich hilft das!


Was ist eine "Deklaration für Abschnitt"? Wo setzen Sie diesen Code ein?
Ahnbizcad

1

Ich habe ein .vspaceElement mit einer Höhe von 40 Pixel hinzugefügt , das den Anker vor jedem meiner h1Elemente hält.

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

Im CSS:

.vspace { height: 40px;}

Es funktioniert großartig und der Raum ist nicht voll.


1

Bootstrap 4 (Update 2019)

Implementierung: Nav, Scrollspy und Smooth Scrolling wurden korrigiert

Dies ist die Lösung von @ wilfred-hughes oben, genau behebt das Überlappungsproblem mit der festen Bootstrap-Navigationsleiste, indem CSS ':: before' verwendet wird, um einem nicht angezeigten Block vor jedem Abschnitts-Tag einen Präfix voranzustellen. Vorteil: Sie haben keine unnötige Polsterung zwischen Ihren Abschnitten. Beispielsweise kann Abschnitt 3 vertikal direkt gegenüber Abschnitt 2 positioniert werden, und es wird immer noch zur genau richtigen Position oben in Abschnitt 3 gescrollt.

Randnotiz: Das Festlegen des Scrollspy-Versatzes im Skript-Tag führte dazu, dass nichts passierte ($ ('# navbar'). Scrollspy ({offset: 105});) und Versuche, den Versatz im Animationsblock anzupassen, führten nach wie vor zu einer Fehlausrichtung. Animation.

index.html

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

später in 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;
}

Bildnachweis: @ wilfred-hughes oben und die Originalquelle von Benutzer @mnot unter https://github.com/twbs/bootstrap/issues/1768


Danke! ugh ich habe eine Stunde damit gerungen, LOL!
Nexus

0

Ich hatte Probleme mit den Lösungen von acjohnson55 und Kurt UXD. Beide arbeiteten für das Klicken auf einen Link zum Hash, aber der Scrollspy-Offset war immer noch nicht korrekt.

Ich habe die folgende Lösung gefunden:

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

Und das entsprechende CSS:

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;
  }
}

Sie müssen die 40px-Polsterung / den 40px-Rand durch die Höhe Ihrer Navigationsleiste und die ID Ihres Ankers ersetzen.

In diesem Setup kann ich sogar einen Effekt beim Festlegen eines Werts für das Datenversatzattribut beobachten. Wenn große Werte für den Datenversatz um 100-200 gefunden werden, führt dies zu einem erwarteten Verhalten (der Scrollspy- "Schalter" erfolgt, wenn sich die Überschrift in der Mitte des Bildschirms befindet).

Ich fand auch, dass scrollspy sehr empfindlich auf Fehler wie nicht geschlossene div-Tags reagiert (was ziemlich offensichtlich ist), also war http://validator.w3.org/check mein Freund hier.

Meiner Meinung nach funktioniert scrollspy am besten mit ganzen Abschnitten, die die Anker-ID tragen, da reguläre Ankerelemente beim Rückwärtsblättern nicht zu erwarteten Effekten führen (der scrollspy- "Schalter" erfolgt schließlich, sobald Sie das Ankerelement treffen, z. B. Ihre Überschrift, aber Zu diesem Zeitpunkt haben Sie bereits über den Inhalt gescrollt, von dem der Benutzer erwartet, dass er zur entsprechenden Überschrift gehört.


0

Wenn Sie über diese Frage (wie ich) über Google gestolpert sind und immer noch nach einer Möglichkeit suchen, den Versatz von Scrollspy dynamisch zu ändern. Ich füge jetzt einen Link zu einer Lösung hinzu, die für mich funktioniert hat.

Schauen Sie sich diesen Beitrag an, den ich in einem anderen Thread verfasst habe . Dies enthält einen Ausschnitt darüber, wie Sie den Versatzwert programmgesteuert ändern und dynamisch auf Änderungen reagieren können (z. B. wenn sich die Größe der Navigationsleiste ändert).

Sie müssen nicht an CSS-Korrekturen herumspielen, sondern den aktuell benötigten Offset in Abhängigkeit von bestimmten Ereignissen festlegen.


-1

Sie können auch öffnen bootstap-offset.jsund ändern

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

Dort.


1
Der Scrollspy-Offset versetzt den Inhalt nicht, sondern das Navi.
Markus

-1

Einfach einstellen:

data-offset="200"

data-offsetist standardmäßig "50" und das entspricht 10px. Erhöhen Sie also einfach data-offsetund Ihr Problem ist gelöst.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.