Jak ustawić przesunięcie dla ScrollSpy w Bootstrap?

98

Mam witrynę z paskiem nawigacyjnym na górze i trzema elementami div poniżej w głównym obszarze zawartości.

Próbuję użyć scrollspy z frameworka bootstrap.

Udało mi się podświetlić różne nagłówki w menu, gdy przewijasz elementy div.

Ja też to mam, więc po kliknięciu menu przewinie się do odpowiedniej części strony. Jednak przesunięcie jest nieprawidłowe (nie bierze pod uwagę paska nawigacyjnego, więc muszę przesunąć o około 40 pikseli)

Widzę na stronie Bootstrap, że wspomina o opcji przesunięcia, ale nie jestem pewien, jak jej użyć.

Nie jestem też tym, co to znaczy, gdy mówi, że możesz użyć scrollspy z $('#navbar').scrollspy(), nie jestem pewien, gdzie to uwzględnić, więc nie zrobiłem i wszystko wydaje się działać (z wyjątkiem przesunięcia).

Myślałem, że przesunięcie może być data-offset='10'na tagu body, ale nic to dla mnie nie robi.

Mam wrażenie, że jest to coś naprawdę oczywistego i po prostu mi tego brakuje. Jakaś pomoc?

Mój kod to

...
<!-- 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>
Lango
źródło
Dlaczego podajesz pozycję: względem swoich div? Być może to jest przyczyną tego. Czy możesz utworzyć jsfiddle za pomocą swojego kodu, abyśmy mogli zobaczyć w akcji?
periklis,

Odpowiedzi:

113

Bootstrap używa offsetu tylko do rozpoznawania szpiegowania, a nie przewijania. Oznacza to, że przewijanie do odpowiedniego miejsca zależy od Ciebie.

Spróbuj tego, to działa dla mnie: dodaj procedurę obsługi zdarzeń dla kliknięć nawigacji.

var offset = 80;

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

Znalazłem to tutaj: https://github.com/twitter/bootstrap/issues/3316

Kurt UXD
źródło
3
Dziękuję za odpowiedź. Zajęło mi trochę czasu, zanim zdałem sobie sprawę, że przesunięcie nie wpływa na przewijanie. Oznacza to, że każdy, kto używa stałego blatu, musi ręcznie regulować w ten sposób.
Brian Smith
8
Aby odpowiednio zaktualizować sekcję skrótu adresu URL, dodaj window.location.hash = $(this).attr('href')do tej funkcji.
Stephen M. Harris
2
Dzięki! FWIW, umieszczenie przesunięcia danych w treści jest również ważne, ponieważ pytający mówi, że nic nie robi, ale jest potrzebne do prawidłowego szpiegowania. Pomocna może być wyczerpująca odpowiedź.
mrooney
4
Dynamiczne zwycięstwo: var navOffset = $('#navbar').height();iscrollBy(0, -navOffset);
ahnbizcad
78

Sztuczka, jak wspomniał Tim, polega na wykorzystaniu dopełnienia. Problem polega więc na tym, że Twoja przeglądarka zawsze chce przewinąć zakotwiczenie dokładnie na górę okna. jeśli ustawisz kotwicę w miejscu, w którym faktycznie zaczyna się tekst, zostanie on zasłonięty przez pasek menu. Zamiast tego ustawiasz kotwicę na identyfikator kontenera <section>lub <div>tagu, którego nav / navbar użyje automatycznie. Następnie musisz ustawić padding-topdla kontenera żądaną kwotę przesunięcia, a margin-topdla kontenera przeciwną do padding-top. Teraz twój blok kontenera i kotwica zaczynają się dokładnie na górze strony, ale zawartość wewnątrz zaczyna się dopiero poniżej paska menu.

Jeśli używasz zwykłych kotwic, możesz osiągnąć to samo, używając ujemnego górnego marginesu w kontenerze, jak powyżej, ale bez dopełnienia. Następnie umieszczasz zwykłą <a target="...">kotwicę jako pierwsze dziecko kontenera. Następnie nadajesz styl drugiemu elementowi podrzędnemu przeciwny, ale równy margin-top, ale używając selektora .container:first-child +.

Wszystko to zakłada, że ​​Twój <body>tag ma już ustawiony margines rozpoczynający się poniżej nagłówka, co jest normą (w przeciwnym razie strona byłaby renderowana z przesłoniętym tekstem od razu).

Oto przykład tego w akcji. Wszystko na Twojej stronie, do którego masz identyfikator, może być powiązane, umieszczając # the-elements-id na końcu adresu URL. Jeśli utworzysz wszystkie tagi h ad tagi dt z identyfikatorami umożliwiającymi łączenie (tak jak robi to github ) za pomocą jakiegoś skryptu, który wstawi mały link po lewej stronie ; dodanie następujących elementów do CSS zajmie się przesunięciem paska nawigacyjnego za Ciebie:

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;
}
acjay
źródło
9
Uwielbiam kombinację dopełnienia góra, ujemny margines dolny (na tym samym elemencie). Łatwiej niż bawić się z js.
Eystein
Wygląda na najlepszą odpowiedź, ale jestem trochę zagubiony. Jakaś szansa na przykład.
eddyparkinson
@eddyparkinson, zgadnij, że już to rozgryzłeś: Przykład, kiedy masz swój identyfikator w rzędach bootstrapu: .row [id] {padding-top: 60px; margin-top: -40px; } Umieść to w swoim mniejszym pliku: .row [id] {padding-top: 60px; margin-top: -40px; }
Klaaz,
Czy do tego nie powinien być przypisany domyślny parametr offsetu bootstrapa? To oczywiste, że trzeba to uwzględnić i nie trzeba uciekać się do takich obejść.
ahnbizcad
Czy to skutecznie dodaje dodatkowe miejsce na docelowym div? A jeśli tego nie chcesz? Idealny byłby niewidoczny dodatkowy odstęp.
ahnbizcad
10

Możesz zmienić przesunięcie scrollspy'a w locie dzięki temu (zakładając, że szpiegujesz ciało):

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

Działa to również w przypadku konieczności dynamicznej zmiany wartości przesunięcia. (Lubię, gdy scrollspy przełącza się, gdy następna sekcja znajduje się mniej więcej w połowie okna, więc muszę zmienić przesunięcie podczas zmiany rozmiaru okna).

cogell
źródło
2
Dzięki za to - działa świetnie z niewielkimi zmianami w Bootstrap 3.0 $ ('body'). Data () ['bs.scrollspy']. Options.offset = newOffset; // Ustaw nowe przesunięcie $ ('body'). Data () ['bs.scrollspy']. Process (); // Wymuś scrollspy na przeliczenie przesunięć do Twoich celów $ ('body'). Scrollspy ('refresh'); // Odśwież scrollspy.
Sam
Odkryłem, że ta metoda jest dobra, ale jeśli chcę jej użyć do ustawienia przesunięcia od początku ze względu na różne wysokości menu $ ('body'). Data (). Scrollspy.options.offset (lub wariant dla wersji 3.0) nie jest jeszcze ustawiony. Czy jest coś asynchronicznego w scrollspy, czego mi brakuje?
ness-EE
Od wersji Bootstrap 3.1.1 tak powinno być $('body').data()['bs.scrollspy'].options.offset. Przydatne do wyzwalania scrollspy'u podczas ładowania strony za pomocąwindow.scrollBy(X,Y)
Meredith,
8

Jeśli chcesz przesunąć 10, umieść to w swojej głowie:

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

Twój tag body wyglądałby tak:

<body data-spy="scroll">
David Naffis
źródło
6
To nie kompensuje zawartości, ale przesuwa nawigację.
markus
To zadziała, aby podświetlić właściwy element nawigacyjny, a nie lokalizację, do której prowadzi kliknięcie (co jest oryginalnym pytaniem dotyczącym plakatów). Powiedziawszy to, tego właśnie szukałem! Dzięki!
valin077
6

Z numeru 3316 bootstrap :

[To] ma na celu jedynie modyfikację obliczeń przewijania - nie przesuwamy faktycznego kliknięcia kotwicy

Zatem ustawienie przesunięcia wpływa tylko na to, gdzie scrollspy myśli, że strona jest przewijana . Nie wpływa na przewijanie po kliknięciu znacznika kotwicy.

Korzystanie ze stałego paska nawigacyjnego oznacza, że ​​przeglądarka przewija w niewłaściwe miejsce. Możesz to naprawić za pomocą 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);
});

Aby jednak upewnić się, że scrollspy podświetla właściwy bieżący element, nadal musisz ustawić przesunięcie:

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

Oto kompletne demo na JSFiddle .


Alternatywnie możesz dopełnić znaczniki kotwicy, zgodnie z sugestiami sztuczek 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; 
}
Wilfred Hughes
źródło
1

Myślę, że to przesunięcie może coś zrobić z dolną pozycją sekcji.

Naprawiłem swój problem - taki sam jak twój - dodając

  padding-top: 60px;

w deklaracji sekcji w pliku bootstrap.css

Mam nadzieję, że to pomoże!

Tim
źródło
co to jest „deklaracja dla sekcji” Gdzie umieszczasz ten kod?
ahnbizcad
1

Dodałem .vspaceelement o wysokości 40px trzymający kotwicę przed każdym z moich h1elementów.

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

W CSS:

.vspace { height: 40px;}

Działa świetnie, a przestrzeń nie jest zatłoczona.

Quentin
źródło
1

Bootstrap 4 (aktualizacja 2019)

Wdrażanie: Naprawiono nawigację, Scrollspy i płynne przewijanie

Jest to rozwiązanie od @ Wilfred Hughes powyżej, dokładnie rozwiązuje problem nakładania się ze stałym paskiem nawigacyjnym Bootstrap, używając CSS „:: before”, aby blok przed każdym znacznikiem sekcji. Zaleta: nie kończy się niepotrzebnym wypełnieniem między sekcjami. Np. Sekcja 3 może być ustawiona pionowo naprzeciw sekcji 2 i nadal będzie przewijać się do dokładnej prawidłowej pozycji na górze sekcji 3.

Nota boczna: ustawienie przesunięcia scrollspy w tagu skryptu nie spowodowało, że nic się nie wydarzyło ($ ('# navbar'). Scrollspy ({offset: 105});) i próby dostosowania przesunięcia w bloku animacji nadal skutkowały niewspółosiowością. animacja.

index.html

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

później w 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;
}

Źródło: @ wilfred-hughes powyżej i oryginalne źródło od użytkownika @mnot na https://github.com/twbs/bootstrap/issues/1768

ObjectiveTC
źródło
1
Dziękuję Ci! ugh, zmagałem się z tym przez godzinę, LOL!
Nexus
0

Miałem problemy z rozwiązaniami acjohnson55 i Kurt UXD. Oba działały, aby kliknąć link do skrótu, ale przesunięcie scrollspy nadal nie było poprawne.

Wymyśliłem następujące rozwiązanie:

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

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

Będziesz musiał zastąpić wypełnienie / margines 40 pikseli wysokością paska nawigacyjnego i identyfikatorem kotwicy.

W tej konfiguracji mogę nawet zaobserwować efekt ustawienia wartości atrybutu przesunięcia danych. Jeśli znajdziesz duże wartości przesunięcia danych w okolicach 100-200, prowadzi to do bardziej oczekiwanego zachowania (przewijanie szpiegowskie- "przełączenie" nastąpi, jeśli nagłówek znajduje się mniej więcej pośrodku ekranu).

Odkryłem również, że scrollspy jest bardzo wrażliwy na błędy, takie jak niezamknięte znaczniki DIV (co jest dość oczywiste), więc http://validator.w3.org/check był moim przyjacielem.

Moim zdaniem scrollspy działa najlepiej z całymi sekcjami niosącymi identyfikator kotwicy, ponieważ zwykłe elementy kotwicy nie prowadzą do oczekiwanych efektów podczas przewijania do tyłu (scrollspy - "przełącznik" w końcu następuje, gdy tylko trafisz w element kotwicy, np. Nagłówek, ale w tym czasie przewinąłeś już zawartość, której użytkownik spodziewa się, że należy do odpowiedniego nagłówka).

schreon
źródło
0

Jeśli natknąłeś się na to pytanie (tak jak ja) przez Google i nadal szukasz sposobu na dynamiczną zmianę przesunięcia scrollspy. Dołączam teraz link do rozwiązania, które działało dla mnie.

Spójrz na ten post, który zrobiłem w innym wątku . Zawiera krótki opis, w jaki sposób można programowo zmienić wartość przesunięcia i dynamicznie reagować na zmiany (np. Gdy pasek nawigacyjny zmienia rozmiar).

Nie musisz majstrować przy poprawkach CSS, ale raczej ustawić przesunięcie, którego obecnie potrzebujesz w zależności od pewnych zdarzeń.

thex
źródło
-1

Możesz także otwierać bootstap-offset.jsi modyfikować

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

tam.

Cegła suszona na słońcu
źródło
1
Przesunięcie scrollspy nie kompensuje zawartości, przesuwa nawigację.
markus
-1

Wystarczy ustawić:

data-offset="200"

data-offsetma domyślnie wartość „50”, co odpowiada 10 pikselom, więc po prostu zwiększ, data-offseta problem zostanie rozwiązany.

Zivanic
źródło