如何在 Bootstrap 中设置 ScrollSpy 的偏移量?

我有一个网站与导航栏固定在顶部和3迪夫下面的主要内容区域。

我正在尝试使用引导框架中的 scrollspit。

我有它成功地高亮菜单中的不同标题时,你滚动过去的 div。

我也有它,所以当你点击菜单,它将滚动到正确的部分的网页。但是,偏移量不正确(它没有考虑到导航栏,所以我需要偏移大约40像素)

我看到在 引导页它提到了一个偏移选项,但我不知道如何使用它。

我也不知道它是什么意思,当它说你可以使用 scrollspywith $('#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>
119286 次浏览

If you want an offset of 10 you would put this in your head:

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

Your body tag would look like this:

<body data-spy="scroll">

I think that offset might do something with the bottom position of the section.

I fixed my issue - the same as yours - by adding

  padding-top: 60px;

in the declaration for section in bootstrap.css

Hope that helps!

Bootstrap uses offset to resolve spying only, not scrolling. This means that scrolling to the proper place is up to you.

Try this, it works for me: add an event handler for the navigation clicks.

var offset = 80;


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

I found it here: https://github.com/twitter/bootstrap/issues/3316

The trick, as Tim alluded to, is to take advantage of padding. So the problem is, your browser always wants to scroll your anchor to the exact top of the window. if you set your anchor where your text actually begins, it will be occluded by your menu bar. Instead, what you do is set your anchor to the container <section> or <div> tag's id, which the nav/navbar will automatically use. Then you have to set your padding-top for the container to the amount offset you want, and the margin-top for the container to the opposite of the padding-top. Now your container's block and the anchor begin at the exact top of the page, but the content inside doesn't begin until below the menu bar.

If you're using regular anchors, you can accomplish the same thing by using negative margin-top in your container as above, but no padding. Then you put a regular <a target="..."> anchor as the first child of the container. Then you style the second child element with an opposite but equal margin-top, but using the selector .container:first-child +.

This all presumes that your <body> tag already has its margin set to begin below your header, which is the norm (otherwise the page would render with occluded text right off the bat).

Here's an example of this in action. Anything on your page with an id can be linked to by tacking #the-elements-id onto the end of your URL. If you make all of your h tags ad dt tags with ids link-able (Like github does) with some sort of script that injects a little link to the left of them; adding the following to your CSS will take care of the nav-bar offset for you:

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

You can change the offset of scrollspy on the fly with this (assuming you spying on the body):

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

This also works if you need to change the offset value dynamically. (I like the scrollspy to switch over when the next section is about halfway up the window so I need to change the offset during window resize.)

I added 40px-height .vspace element holding the anchor before each of my h1 elements.

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

In the CSS:

.vspace { height: 40px;}

It's working great and the space is not chocking.

I had problems with the solutions of acjohnson55 and Kurt UXD. Both worked for clicking a link to the hash, but the scrollspy offset was still not correct.

I came up with the following solution:

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

And the corresponding 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;
}
}

You will need to replace the 40px padding / margin with the height of your navbar, and the id of your anchor.

In this setup I can even observe an effect of setting a value for the data-offset attribute. If find large values for the data-offset around 100-200 lead to a more expected behavior (the scrollspy-"switch" will happen if the heading is circa in the middle of the screen).

I also found that scrollspy is very sensitive to errors like unclosed div tags (which is quite obvious), so http://validator.w3.org/check was my friend here.

In my opinion scrollspy works best with whole sections carrying the anchor ID, since regular anchor elements do not lead to expected effects when scrolling backwards (the scrollspy-"switch" eventually happens as soon as you hit the anchor element, e.g. your heading, but at that time you have already scrolled over the content which the user expects to belong to the according heading).

You can also open bootstap-offset.js and modify

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

there.

From bootstrap issue #3316:

[This] is only intended to modify scrolling calculations - we don't shift the actual anchor click

So setting offset only affects where scrollspy thinks the page is scrolled to. It doesn't affect scrolling when you click an anchor tag.

Using a fixed navbar means that the browser is scrolling to the wrong place. You can fix this with 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);
});

However, to ensure that scrollspy highlights the correct current element, you still need to set the offset:

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

Here's a complete demo on JSFiddle.


Alternatively, you could padding to your anchor tags, as suggested by CSS tricks.

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

Just set :

data-offset="200"

data-offset is by default "50" and that is equivalent 10px, so just increase data-offset and your problem is solved.

Bootstrap 4 (2019 update)

Implementing: Fixed Nav, Scrollspy, and Smooth Scrolling

This is the solution from @wilfred-hughes above, it exactly fixes the overlap issue with the Bootstrap Fixed Navbar by using CSS '::before' to prepend an non-displayed block before each section tag. Advantage: you don't end up with unnecessary padding between your sections. Eg, section 3 can be vertically positioned right up against section 2 and it will still scroll to the exact correct position at the top of section 3.

Side note: setting the scrollspy offset in the script tag caused nothing to happen ( $('#navbar').scrollspy({ offset: 105 });) and attempts to adjust the offset in the animation block still resulted in misalignment post-animation.

index.html

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

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

Credit: @wilfred-hughes above and the original source from user @mnot at https://github.com/twbs/bootstrap/issues/1768

Take a look on this post I made in another thread. This contains a snippet on how you can programmatically change the offset value and dynamically react on changes (e.g. if the navbar changes in size).

You don't need to tinker around with CSS fixes but rather set the offset you currently need in dependence of certain events.

In Bootstrap v5.1.3 I have used data-bs-offset="xxx" on the body element in my project and it works perfectly.

Example:

<body data-bs-spy="scroll"
data-bs-target="#navbar-scrollspy"
data-bs-offset="100">                 <<== see here


<nav class="navbar fixed-top" id="navbar-scrollspy">
...
</nav>


...


</body>

NO CSS and content elements need to be changes. Try this code:

$(document).ready(function () {
nav_top = $("#tsnav");
offset = 10; // get extra space
side_nav = $("#cve_info") // functional nav
top_height = nav_top.outerHeight() + offset; // get the top navbar hieght + get extra space


side_nav.find("a").on('click', function () {
let $el = $(this);
id = $el.attr("href");


$('html, body').scrollTop( $(id).offset().top - top_height);
return false;
})

});