Bagaimana cara mengatur offset ScrollSpy di Bootstrap?

98

Saya memiliki situs dengan bilah navigasi tetap di atas dan 3 div di bawahnya di area konten utama.

Saya mencoba menggunakan scrollspy dari kerangka bootstrap.

Saya memilikinya dengan sukses menyoroti berbagai judul di menu saat Anda menggulir melewati divs.

Saya juga memilikinya sehingga ketika Anda mengklik menu, itu akan menggulir ke bagian halaman yang benar. Namun, offsetnya salah (Ini tidak memperhitungkan bilah navigasi, jadi saya perlu mengimbangi sekitar 40 piksel)

Saya melihat di halaman Bootstrap yang menyebutkan opsi offset tetapi saya tidak yakin bagaimana menggunakannya.

Saya juga tidak mengerti maksudnya ketika dikatakan Anda dapat menggunakan scrollspy dengan $('#navbar').scrollspy(), saya tidak yakin di mana harus memasukkannya jadi saya tidak dan semuanya tampaknya berfungsi (kecuali offset).

Saya pikir offsetnya mungkin data-offset='10'pada tag bodi, tetapi tidak melakukan apa-apa untuk saya.

Saya merasa ini adalah sesuatu yang sangat jelas dan saya melewatkannya. Ada bantuan?

Kode saya adalah

...
<!-- 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
sumber
Mengapa Anda memberikan posisi: relatif terhadap div Anda? Mungkin itulah yang menyebabkan ini. Bisakah Anda membuat jsfiddle dengan kode Anda sehingga kita bisa melihatnya beraksi?
periklis

Jawaban:

113

Bootstrap menggunakan offset untuk menyelesaikan spionase saja, bukan scrolling. Artinya, menggulir ke tempat yang tepat terserah Anda.

Coba ini, ini berfungsi untuk saya: tambahkan pengendali peristiwa untuk klik navigasi.

var offset = 80;

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

Saya menemukannya di sini: https://github.com/twitter/bootstrap/issues/3316

Kurt UXD
sumber
3
Terima kasih atas jawabannya. Butuh waktu cukup lama bagi saya untuk menyadari bahwa offset tidak memengaruhi scrolling. Ini berarti siapa pun yang menggunakan fixed-top perlu menyesuaikan secara manual dengan cara ini.
Brian Smith
8
Untuk memperbarui bagian hash dari URL dengan tepat, tambahkan window.location.hash = $(this).attr('href')fungsi ini.
Stephen M. Harris
2
Terima kasih! FWIW, menempatkan data-offset di tubuh juga penting, karena penanya mengatakan tidak melakukan apa-apa, tetapi diperlukan untuk mata-mata yang tepat. Mungkin membantu untuk memiliki jawaban yang komprehensif.
mrooney
4
Kemenangan dinamis: var navOffset = $('#navbar').height();danscrollBy(0, -navOffset);
ahnbizcad
78

Triknya, seperti yang disinggung Tim, adalah memanfaatkan padding. Jadi masalahnya, browser Anda selalu ingin menggulirkan jangkar Anda ke bagian atas jendela. jika Anda mengatur jangkar di tempat teks Anda sebenarnya dimulai, itu akan ditutup oleh bilah menu Anda. Sebaliknya, yang Anda lakukan adalah menyetel jangkar ke wadah <section>atau <div>id tag, yang akan digunakan secara otomatis oleh nav / navbar. Kemudian Anda harus mengatur padding-topwadah Anda ke jumlah offset yang Anda inginkan, dan margin-topuntuk wadah kebalikan dari padding-top. Sekarang blok penampung Anda dan jangkar dimulai tepat di bagian atas halaman, tetapi konten di dalamnya tidak dimulai sampai di bawah bilah menu.

Jika Anda menggunakan jangkar biasa, Anda dapat mencapai hal yang sama dengan menggunakan margin-top negatif di wadah Anda seperti di atas, tetapi tanpa bantalan. Kemudian Anda memasang <a target="...">jangkar biasa sebagai anak pertama dari wadah tersebut. Kemudian Anda memberi gaya pada elemen anak kedua dengan kebalikan tetapi sama margin-top, tetapi menggunakan selektor .container:first-child +.

Ini semua menganggap bahwa <body>tag Anda sudah memiliki margin yang ditetapkan untuk dimulai di bawah header Anda, yang merupakan norma (jika tidak, halaman akan dirender dengan teks yang tertutup langsung dari kelelawar).

Berikut adalah contoh penerapannya. Apa pun di halaman Anda dengan id dapat ditautkan dengan menempelkan # the-elements-id ke akhir URL Anda. Jika Anda membuat semua tag h Anda ad dt tag dengan id yang dapat ditautkan ( Seperti yang dilakukan github ) dengan semacam skrip yang memasukkan sedikit tautan di sebelah kiri mereka ; menambahkan yang berikut ini ke CSS Anda akan menangani offset bilah navigasi untuk Anda:

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.dll
sumber
9
Suka kombo padding-top, margin-bottom negatif (pada elemen yang sama). Lebih mudah kemudian bermain-main dengan js.
Eystein
Sepertinya jawaban terbaik, tapi saya agak bingung. Setiap peluang contoh.
eddyparkinson
@eddyparkinson, coba tebak Anda mengetahuinya sekarang: Contoh, ketika Anda memiliki id Anda di baris bootstrap: .row [id] {padding-top: 60px; margin-top: -40px; } Taruh ini di file less: .row [id] {padding-top: 60px; margin-top: -40px; }
Klaaz
Bukankah parameter offset default bootstrap seharusnya untuk ini? Sepertinya hal yang jelas untuk disertakan, dan tidak harus menggunakan solusi seperti ini.
ahnbizcad
Apakah ini secara efektif menambah ruang ekstra pada div yang Anda targetkan? Bagaimana jika Anda tidak menginginkannya? Jarak ekstra yang tidak terlihat akan ideal.
ahnbizcad
10

Anda dapat mengubah offset scrollspy dengan cepat (dengan asumsi Anda memata-matai tubuh):

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

Ini juga berfungsi jika Anda perlu mengubah nilai offset secara dinamis. (Saya suka scrollspy untuk beralih ketika bagian berikutnya sekitar setengah jendela jadi saya perlu mengubah offset selama pengubahan ukuran jendela.)

cogell
sumber
2
Terima kasih untuk ini - bekerja sangat baik dengan sedikit penyesuaian untuk Bootstrap 3.0 $ ('body']. Data () ['bs.scrollspy']. Options.offset = newOffset; // Setel offset baru $ ('body'). Data () ['bs.scrollspy']. Process (); // Paksa scrollspy untuk menghitung ulang offset ke target Anda $ ('body'). Scrollspy ('refresh'); // Segarkan scrollspy.
Sam
Saya telah menemukan bahwa metode ini bagus, tetapi jika saya ingin menggunakannya untuk mengatur offset dari awal karena memiliki ketinggian menu yang berbeda, $ ('body'). Data (). Scrollspy.options.offset (atau varian untuk versi 3.0) belum disetel. Apakah ada sesuatu yang tidak sinkron tentang scrollspy yang saya lewatkan?
ness-EE
Pada Bootstrap 3.1.1 ini seharusnya $('body').data()['bs.scrollspy'].options.offset. Berguna untuk memicu scrollspy pada pemuatan halaman dengan menggunakanwindow.scrollBy(X,Y)
Meredith
8

Jika Anda menginginkan offset 10 Anda akan meletakkan ini di kepala Anda:

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

Tag tubuh Anda akan terlihat seperti ini:

<body data-spy="scroll">
David Naffis
sumber
6
Itu tidak mengimbangi konten, itu mengimbangi navigasi.
markus
Ini akan bekerja untuk menyorot elemen navigasi yang benar dan bukan lokasi di mana klik mengarah (yang merupakan pertanyaan poster asli). Dengan begitu, inilah yang saya cari! Terima kasih!
valin077
6

Dari masalah bootstrap # 3316 :

[Ini] hanya dimaksudkan untuk mengubah kalkulasi pengguliran - kami tidak menggeser klik jangkar yang sebenarnya

Jadi pengaturan offset hanya mempengaruhi di mana scrollspy menganggap halaman digulir . Itu tidak mempengaruhi pengguliran saat Anda mengeklik tag jangkar.

Menggunakan bilah navigasi tetap berarti browser menggulir ke tempat yang salah. Anda dapat memperbaikinya dengan 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);
});

Namun, untuk memastikan bahwa scrollspy menyoroti elemen saat ini dengan benar, Anda masih perlu menyetel offset:

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

Berikut demo lengkapnya di JSFiddle .


Sebagai alternatif, Anda dapat mengisi tag anchor Anda, seperti yang disarankan oleh trik 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
sumber
1

Saya pikir offset itu mungkin melakukan sesuatu dengan posisi bawah bagian.

Saya memperbaiki masalah saya - sama seperti masalah Anda - dengan menambahkan

  padding-top: 60px;

di deklarasi untuk bagian di bootstrap.css

Semoga membantu!

Tim
sumber
apa yang dimaksud dengan "deklarasi untuk bagian" Di mana Anda meletakkan kode ini?
ahnbizcad
1

Saya menambahkan .vspaceelemen 40px-height yang menahan jangkar di depan setiap h1elemen saya .

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

Di CSS:

.vspace { height: 40px;}

Ini berfungsi dengan baik dan ruang tidak sesak.

Quentin
sumber
1

Bootstrap 4 (pembaruan 2019)

Menerapkan: Memperbaiki Nav, Scrollspy, dan Smooth Scrolling

Ini solusi dari @ wilfred-hughes di atas, tepatnya memperbaiki masalah yang tumpang tindih dengan Bootstrap Fixed Navbar dengan menggunakan CSS ':: before' untuk menambahkan blok yang tidak ditampilkan sebelum setiap tag bagian. Keuntungan: Anda tidak akan mendapatkan bantalan yang tidak perlu di antara bagian Anda. Misalnya, bagian 3 dapat diposisikan secara vertikal tepat di atas bagian 2 dan masih akan bergulir ke posisi yang benar-benar tepat di atas bagian 3.

Catatan samping: menyetel offset scrollspy di tag skrip tidak menyebabkan apa pun terjadi ($ ('# navbar'). Scrollspy ({offset: 105});) dan upaya untuk menyesuaikan offset di blok animasi masih mengakibatkan ketidaksejajaran pasca- animasi.

index.html

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

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

Kredit: @ wilfred-hughes di atas dan sumber asli dari pengguna @mnot di https://github.com/twbs/bootstrap/issues/1768

ObjectiveTC
sumber
1
Terima kasih! ugh aku sudah bergulat dengan ini selama satu jam, LOL!
Nexus
0

Saya mengalami masalah dengan solusi dari acjohnson55 dan Kurt UXD. Keduanya bekerja untuk mengklik link ke hash, tetapi scrollspy offset masih belum benar.

Saya datang dengan solusi berikut:

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

Dan CSS yang sesuai:

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

Anda perlu mengganti padding / margin 40px dengan tinggi navbar Anda, dan id dari jangkar Anda.

Dalam pengaturan ini saya bahkan dapat mengamati efek pengaturan nilai untuk atribut data-offset. Jika menemukan nilai besar untuk data-offset sekitar 100-200 mengarah ke perilaku yang lebih diharapkan (scrollspy- "switch" akan terjadi jika heading ada di tengah layar).

Saya juga menemukan bahwa scrollspy sangat sensitif terhadap kesalahan seperti tag div yang tidak ditutup (yang cukup jelas), jadi http://validator.w3.org/check adalah teman saya di sini.

Menurut pendapat saya scrollspy bekerja paling baik dengan seluruh bagian yang membawa ID jangkar, karena elemen jangkar biasa tidak mengarah pada efek yang diharapkan saat menggulir ke belakang (scrollspy- "switch" akhirnya terjadi segera setelah Anda menekan elemen jangkar, misalnya tajuk Anda, tetapi pada saat itu Anda telah menggulir konten yang diharapkan pengguna termasuk dalam judul yang sesuai).

Schreon
sumber
0

Jika Anda tersandung pertanyaan ini (seperti yang saya lakukan) melalui Google dan masih mencari cara untuk secara dinamis mengubah offset scrollspy. Saya sekarang melampirkan tautan ke solusi yang berhasil untuk saya.

Lihatlah posting yang saya buat di utas lain . Ini berisi potongan tentang bagaimana Anda dapat mengubah nilai offset secara terprogram dan secara dinamis bereaksi terhadap perubahan (misalnya jika bilah navigasi berubah ukuran).

Anda tidak perlu mengutak-atik perbaikan CSS, melainkan mengatur offset yang saat ini Anda butuhkan dalam ketergantungan peristiwa tertentu.

thex
sumber
-1

Anda juga dapat membuka bootstap-offset.jsdan memodifikasi

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

sana.

Adobe
sumber
1
Scrollspy offset tidak mengimbangi konten, ia mengimbangi nav.
markus
-1

Setel saja:

data-offset="200"

data-offsetsecara default adalah "50" dan itu setara dengan 10px, jadi naikkan saja data-offsetdan masalah Anda terpecahkan.

Zivanic
sumber