ฉันจะตั้งค่าออฟเซ็ตสำหรับ ScrollSpy ใน Bootstrap ได้อย่างไร


98

ฉันมีไซต์ที่มีแถบนำทางอยู่ด้านบนและ 3 div ด้านล่างในพื้นที่เนื้อหาหลัก

ฉันพยายามใช้ scrollspy จาก bootstrap framework

ฉันประสบความสำเร็จในการไฮไลต์ส่วนหัวต่างๆในเมนูเมื่อคุณเลื่อนผ่าน div

ฉันก็มีเช่นกันเมื่อคุณคลิกเมนูมันจะเลื่อนไปยังส่วนที่ถูกต้องของหน้า อย่างไรก็ตามออฟเซ็ตไม่ถูกต้อง (ไม่ได้คำนึงถึงแถบนำทางดังนั้นฉันต้องชดเชยประมาณ 40 พิกเซล)

ฉันเห็นในหน้า Bootstrapระบุถึงตัวเลือกออฟเซ็ต แต่ฉันไม่แน่ใจว่าจะใช้อย่างไร

ฉันก็ไม่ได้หมายความเช่นกันเมื่อมันบอกว่าคุณสามารถใช้ scrollspy ด้วย$('#navbar').scrollspy()ฉันไม่แน่ใจว่าจะรวมไว้ที่ไหนดังนั้นฉันจึงไม่ได้ทำและดูเหมือนว่าทุกอย่างจะใช้งานได้ (ยกเว้นออฟเซ็ต)

ฉันคิดว่าการชดเชยอาจเป็นdata-offset='10'แท็กบนร่างกาย แต่มันไม่ได้ทำอะไรให้ฉัน

ฉันรู้สึกว่านี่เป็นสิ่งที่ชัดเจนจริงๆและฉันแค่คิดถึงมัน ความช่วยเหลือใด ๆ

รหัสของฉันคือ

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

เหตุใดคุณจึงให้ตำแหน่ง: สัมพันธ์กับ div ของคุณ บางทีนั่นอาจเป็นสาเหตุของสิ่งนี้ คุณสามารถสร้าง jsfiddle ด้วยรหัสของคุณเพื่อให้เราเห็นในการดำเนินการได้หรือไม่?
periklis

คำตอบ:


114

Bootstrap ใช้ออฟเซ็ตเพื่อแก้ไขการสอดแนมเท่านั้นไม่ใช่การเลื่อน ซึ่งหมายความว่าการเลื่อนไปยังตำแหน่งที่เหมาะสมนั้นขึ้นอยู่กับคุณ

ลองวิธีนี้ใช้ได้กับฉัน: เพิ่มตัวจัดการเหตุการณ์สำหรับการคลิกการนำทาง

var offset = 80;

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

ฉันพบที่นี่: https://github.com/twitter/bootstrap/issues/3316


3
ขอบคุณสำหรับคำตอบ. ใช้เวลาพอสมควรในการตระหนักว่าการชดเชยไม่มีผลต่อการเลื่อน ซึ่งหมายความว่าใครก็ตามที่ใช้ fixed-top จำเป็นต้องปรับด้วยตนเองในลักษณะนี้
Brian Smith

9
หากต้องการอัปเดตส่วนแฮชของ URL อย่างเหมาะสมให้เพิ่มwindow.location.hash = $(this).attr('href')ฟังก์ชันนี้
Stephen M. Harris

2
ขอบคุณ! FWIW การใส่ data-offset ในร่างกายก็สำคัญเช่นกันเนื่องจากผู้ถามบอกว่าไม่ได้ทำอะไรเลย แต่จำเป็นสำหรับการสอดแนมอย่างเหมาะสม อาจช่วยได้คำตอบที่ครอบคลุม
mrooney

4
การชนะแบบไดนามิก: var navOffset = $('#navbar').height();และscrollBy(0, -navOffset);
ahnbizcad

79

เคล็ดลับตามที่ทิมกล่าวถึงคือการใช้ประโยชน์จากช่องว่างภายใน ดังนั้นปัญหาคือเบราว์เซอร์ของคุณต้องการเลื่อนจุดยึดไปที่ด้านบนสุดของหน้าต่างเสมอ หากคุณตั้งจุดยึดที่ข้อความของคุณเริ่มต้นจริงแถบเมนูจะถูกปิดไว้ สิ่งที่คุณทำคือตั้งค่าจุดยึดของคุณเป็นคอนเทนเนอร์<section>หรือ<div>id ของแท็กซึ่ง nav / navbar จะใช้โดยอัตโนมัติ จากนั้นคุณต้องตั้งค่าpadding-topสำหรับคอนเทนเนอร์ของคุณเป็นจำนวนเงินที่ชดเชยที่คุณต้องการและmargin-topสำหรับคอนเทนเนอร์นั้นตรงกันข้ามกับpadding-top. ตอนนี้บล็อกของคอนเทนเนอร์และจุดยึดเริ่มต้นที่ด้านบนสุดของหน้า แต่เนื้อหาข้างในจะไม่เริ่มต้นจนกว่าจะอยู่ใต้แถบเมนู

หากคุณใช้แองเคอร์ปกติคุณสามารถทำสิ่งเดียวกันให้สำเร็จได้โดยใช้ขอบลบด้านบนในคอนเทนเนอร์ของคุณตามด้านบน แต่ไม่มีช่องว่างภายใน จากนั้นให้ใส่<a target="...">สมอธรรมดาเป็นลูกแรกของภาชนะ แล้วคุณสไตล์องค์ประกอบลูกคนที่สองกับตรงข้าม แต่เท่ากับแต่ใช้ตัวเลือกmargin-top.container:first-child +

ทั้งหมดนี้ถือว่า<body>แท็กของคุณมีระยะขอบที่กำหนดไว้แล้วให้เริ่มต้นใต้ส่วนหัวของคุณซึ่งเป็นบรรทัดฐาน (มิฉะนั้นหน้าเว็บจะแสดงผลด้วยข้อความที่ถูกปิดทับทันที)

นี่คือตัวอย่างของการดำเนินการนี้ ทุกสิ่งบนเพจของคุณที่มี id สามารถเชื่อมโยงได้โดยการใส่ # the-elements-id ที่ท้าย URL ของคุณ ถ้าคุณทำแท็กทั้งหมดของ dt โฆษณาเอชแท็กของคุณด้วยรหัสสามารถเชื่อมโยงได้ ( เช่นเดียวกับ GitHub ไม่ ) มีการจัดเรียงของสคริปต์บางอย่างที่เชื่อมโยงแทรกเล็ก ๆ น้อย ๆ ไปทางซ้ายของพวกเขา ; การเพิ่มสิ่งต่อไปนี้ใน CSS ของคุณจะดูแลออฟเซ็ตแถบนำทางให้คุณ:

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
ชอบคำสั่งผสมขอบด้านบนด้านลบด้านล่าง (ในองค์ประกอบเดียวกัน) ง่ายกว่าแล้วยุ่งกับ js
Eystein

ดูเหมือนคำตอบที่ดีที่สุด แต่ฉันหลงทางนิดหน่อย โอกาสของตัวอย่างใด ๆ
eddyparkinson

@eddyparkinson เดาว่าคุณคงคิดออกแล้ว: ตัวอย่างเมื่อคุณมี id ของคุณในแถว bootstrap: .row [id] {padding-top: 60px; ขอบด้านบน: -40px; } ใส่สิ่งนี้ในไฟล์ที่น้อยกว่าของคุณ: .row [id] {padding-top: 60px; ขอบด้านบน: -40px; }
Klaaz

พารามิเตอร์ออฟเซ็ตเริ่มต้นของ bootstrap ไม่ควรเป็นสำหรับสิ่งนี้หรือไม่? ดูเหมือนจะเป็นสิ่งที่ชัดเจนที่จะรวมไว้และไม่จำเป็นต้องใช้วิธีแก้ปัญหาเช่นนี้
ahnbizcad

สิ่งนี้เพิ่มพื้นที่พิเศษใน div ที่คุณกำหนดเป้าหมายได้อย่างมีประสิทธิภาพหรือไม่ ถ้าคุณไม่ต้องการสิ่งนั้นล่ะ? การเว้นระยะห่างพิเศษที่มองไม่เห็นจะเหมาะอย่างยิ่ง
ahnbizcad

10

คุณสามารถเปลี่ยนออฟเซ็ตของ scrollspy ได้ทันทีด้วยสิ่งนี้ (สมมติว่าคุณสอดแนมร่างกาย):

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

วิธีนี้ใช้ได้เช่นกันหากคุณต้องการเปลี่ยนค่าออฟเซ็ตแบบไดนามิก (ฉันชอบให้ scrollspy สลับไปมาเมื่อส่วนถัดไปอยู่ประมาณครึ่งหนึ่งของหน้าต่างดังนั้นฉันต้องเปลี่ยนออฟเซ็ตระหว่างการปรับขนาดหน้าต่าง)


2
ขอบคุณสำหรับสิ่งนี้ - ใช้งานได้ดีกับการปรับแต่งเล็กน้อยสำหรับ Bootstrap 3.0 $ ('body') data () ['bs.scrollspy']. options.offset = newOffset; // ตั้งค่าชดเชยใหม่ $ ('body'). data () ['bs.scrollspy']. process (); // บังคับให้ scrollspy คำนวณค่าชดเชยให้กับเป้าหมายของคุณใหม่ $ ('body') scrollspy ('refresh'); // รีเฟรช scrollspy
แซม

ฉันพบว่าวิธีนี้ดี แต่ถ้าฉันต้องการใช้มันเพื่อตั้งค่าออฟเซ็ตตั้งแต่เริ่มต้นเนื่องจากมีเมนูที่มีความสูงต่างกัน $ ('body') data (). scrollspy.options.offset (หรือ ยังไม่ได้ตั้งค่าตัวแปรสำหรับเวอร์ชัน 3.0) มีบางสิ่งที่ไม่ตรงกันเกี่ยวกับ scrollspy ที่ฉันขาดหายไปหรือไม่?
ness-EE

ในฐานะของเงินทุน 3.1.1 $('body').data()['bs.scrollspy'].options.offsetนี้ควรจะเป็น มีประโยชน์สำหรับการเรียกใช้ scrollspy ในการโหลดหน้าเว็บโดยใช้window.scrollBy(X,Y)
Meredith

8

หากคุณต้องการออฟเซ็ต 10 คุณจะใส่สิ่งนี้ไว้ในหัว:

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

แท็กร่างกายของคุณจะมีลักษณะดังนี้:

<body data-spy="scroll">

6
ซึ่งไม่ได้หักล้างเนื้อหา แต่จะชดเชยการนำทาง
markus

วิธีนี้จะใช้สำหรับเน้นองค์ประกอบการนำทางที่ถูกต้องไม่ใช่ตำแหน่งที่การคลิกนำไปสู่ ​​(ซึ่งเป็นคำถามของผู้โพสต์ดั้งเดิม) เมื่อพูดอย่างนั้นนี่คือสิ่งที่ฉันกำลังมองหา! ขอบคุณ!
valin077

7

จากปัญหา bootstrap # 3316 :

[นี้] มีไว้เพื่อแก้ไขการคำนวณการเลื่อนเท่านั้น - เราไม่ได้เลื่อนการคลิกจุดยึดจริง

ดังนั้นการตั้งค่าชดเชยผลเฉพาะที่ scrollspy คิดว่าหน้าจะเลื่อนไป มันไม่ได้ส่งผลกระทบต่อการเลื่อนเมื่อคุณคลิกแท็กสมอ

การใช้แถบนำทางแบบคงที่หมายความว่าเบราว์เซอร์กำลังเลื่อนไปยังตำแหน่งที่ไม่ถูกต้อง คุณสามารถแก้ไขได้ด้วย 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);
});

อย่างไรก็ตามเพื่อให้แน่ใจว่า scrollspy ไฮไลต์องค์ประกอบปัจจุบันที่ถูกต้องคุณยังคงต้องตั้งค่าชดเชย:

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

นี่คือตัวอย่างที่สมบูรณ์แบบบน JSFiddle


หรือคุณสามารถ padding เพื่อสมอแท็กของคุณเช่นการแนะนำโดยเทคนิค 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

ฉันคิดว่าการชดเชยอาจทำอะไรบางอย่างกับตำแหน่งด้านล่างของส่วน

ฉันแก้ไขปัญหาของฉัน - เช่นเดียวกับของคุณ - โดยการเพิ่ม

  padding-top: 60px;

ในการประกาศสำหรับส่วนใน bootstrap.css

หวังว่าจะช่วยได้!


"การประกาศสำหรับส่วน" คืออะไรคุณใส่รหัสนี้ไว้ที่ไหน
ahnbizcad

1

ฉันเพิ่ม.vspaceองค์ประกอบความสูง 40px ที่ยึดจุดยึดไว้ก่อนh1องค์ประกอบแต่ละส่วนของฉัน

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

ใน CSS:

.vspace { height: 40px;}

มันใช้งานได้ดีและพื้นที่ไม่น่าเบื่อ


1

Bootstrap 4 (อัปเดต 2019)

การใช้งาน: แก้ไข Nav, Scrollspy และ Smooth Scrolling

นี่คือวิธีการแก้ปัญหาจาก @ วิลเฟรดฮิวจ์-ที่กล่าวมานั้นว่าแก้ไขปัญหาทับซ้อนกับ Navbar เงินทุนคงที่โดยใช้ CSS :: ก่อน 'ต้องเพิ่มบล็อกที่ไม่แสดงก่อนแท็กแต่ละส่วน ข้อได้เปรียบ: คุณไม่ต้องลงเอยด้วยการเติมช่องว่างที่ไม่จำเป็นระหว่างส่วนของคุณ เช่นส่วนที่ 3 สามารถวางในแนวตั้งตรงกับส่วนที่ 2 และจะยังคงเลื่อนไปยังตำแหน่งที่ถูกต้องที่ด้านบนของส่วนที่ 3

หมายเหตุด้านข้าง: การตั้งค่าออฟเซ็ต scrollspy ในแท็กสคริปต์ทำให้ไม่มีอะไรเกิดขึ้น ($ ('# navbar'). scrollspy ({offset: 105});) และการพยายามปรับออฟเซ็ตในบล็อกภาพเคลื่อนไหวยังคงส่งผลให้โพสต์ไม่ตรงแนว - ภาพเคลื่อนไหว

index.html

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

ต่อมาใน 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;
}

เครดิต: @ wilfred-hughes ด้านบนและแหล่งที่มาเดิมจากผู้ใช้ @mnot ที่https://github.com/twbs/bootstrap/issues/1768


1
ขอบคุณ! ฮึฉันต่อสู้กับเรื่องนี้มาหนึ่งชั่วโมงแล้วฮ่า ๆ !
Nexus

0

ฉันมีปัญหากับวิธีแก้ปัญหาของ acjohnson55 และ Kurt UXD ทั้งสองทำงานในการคลิกลิงก์ไปยังแฮ แต่ออฟเซ็ต scrollspy ยังไม่ถูกต้อง

ฉันคิดวิธีแก้ปัญหาต่อไปนี้:

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

และ 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;
  }
}

คุณจะต้องแทนที่ 40px padding / margin ด้วยความสูงของ navbar ของคุณและ id ของจุดยึดของคุณ

ในการตั้งค่านี้ฉันสามารถสังเกตผลของการตั้งค่าสำหรับแอตทริบิวต์ data-offset หากพบค่าขนาดใหญ่สำหรับ data-offset ประมาณ 100-200 จะนำไปสู่พฤติกรรมที่คาดหวังมากขึ้น (scrollspy- "switch" จะเกิดขึ้นหากส่วนหัวอยู่ประมาณกลางหน้าจอ)

ฉันยังพบว่า scrollspy มีความไวต่อข้อผิดพลาดมากเช่นแท็ก div ที่ไม่ปิด (ซึ่งค่อนข้างชัดเจน) ดังนั้นhttp://validator.w3.org/checkจึงเป็นเพื่อนของฉันที่นี่

ในความคิดของฉัน scrollspy ทำงานได้ดีที่สุดกับทั้งส่วนที่มี Anchor ID เนื่องจากองค์ประกอบจุดยึดปกติไม่ได้นำไปสู่ผลกระทบที่คาดหวังเมื่อเลื่อนไปข้างหลัง (ในที่สุด scrollspy- "สวิตช์" จะเกิดขึ้นทันทีที่คุณกดองค์ประกอบจุดยึดเช่นส่วนหัวของคุณ แต่ ในขณะนั้นคุณได้เลื่อนดูเนื้อหาที่ผู้ใช้คาดว่าจะอยู่ในหัวข้อตาม)


0

หากคุณพบคำถามนี้ (เช่นเดียวกับที่ฉันทำ) ผ่าน Google และยังคงค้นหาวิธีเปลี่ยนออฟเซ็ตของ scrollspy แบบไดนามิก ตอนนี้ฉันแนบลิงค์ไปยังโซลูชันที่ใช้ได้ผลสำหรับฉัน

ลองดูเกี่ยวกับเรื่องนี้โพสต์ที่ฉันทำในหัวข้ออื่น สิ่งนี้มีตัวอย่างข้อมูลเกี่ยวกับวิธีที่คุณสามารถเปลี่ยนค่าออฟเซ็ตโดยทางโปรแกรมและตอบสนองต่อการเปลี่ยนแปลงแบบไดนามิก (เช่นหากแถบนำทางเปลี่ยนขนาด)

คุณไม่จำเป็นต้องใช้คนจรจัดกับการแก้ไข CSS แต่ควรตั้งค่าชดเชยที่คุณต้องการในปัจจุบันโดยพึ่งพาเหตุการณ์บางอย่าง


-1

คุณยังสามารถเปิดbootstap-offset.jsและแก้ไข

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

นั่นเอง


1
ค่าออฟเซ็ต scrollspy ไม่ได้หักล้างเนื้อหา แต่จะชดเชยการนำทาง
markus

-1

เพียงแค่ตั้งค่า:

data-offset="200"

data-offsetโดยค่าเริ่มต้นคือ "50" และเท่ากับ 10px ดังนั้นเพียงแค่เพิ่มขึ้นdata-offsetและปัญหาของคุณจะได้รับการแก้ไข

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.