I found this javascript code for smooth scrolling
window.smoothScroll = function(target) {
var scrollContainer = target;
do { //find scroll container
scrollContainer = scrollContainer.parentNode;
if (!scrollContainer) return;
scrollContainer.scrollTop += 1;
} while (scrollContainer.scrollTop == 0);
var targetY = 0;
do { //find the top of target relatively to the container
if (target == scrollContainer) break;
targetY += target.offsetTop;
} while (target = target.offsetParent);
scroll = function(c, a, b, i) {
i++; if (i > 30) return;
c.scrollTop = a + (b - a) / 30 * i;
setTimeout(function(){ scroll(c, a, b, i); }, 20);
}
// start scrolling
scroll(scrollContainer, scrollContainer.scrollTop, targetY, 0);
}
and made simple example here.
As you can see it is scrolling to the red section but it doesn't exclude the height of the navbar. Start of red section goes all up to the top of the page, under navbar.
How to add offset to this script so the red section stops when hit navbar? The padding is not an option, I already tried that and it doesn't look good. Also I need this in vanila javascript, not jquery.
Thanks in advance!
Have a look at this, it calculates the height of the header and later subtracts it from the scroll position :
header = document.querySelectorAll('.navbar'),
space = header[0].clientHeight;
...
var targetY = -space;
Update - requested feature in the comment to redefine the offset. For that I've made targetY
a global variable, it can de updated by executing a function. So in the script where the class gets toggled on scroll, after that happens just add a line with headerSpace();
and it will recalculate the height. From what I read, the initial class also remains so it should work without any further adjustment.
The inline script on the button was also removed and made into an event listener...
Final version - implementation of requestAnimationFrame
which will make the animation smoother and also be easier on the CPU. The original function is left in place as a fallback for when the feature isn't available. Duration can be set with the variable at the top (with 600ms now matches the 30 steps of 20ms that was set before). Also thought it might be handy to put the header height check inside the button click event handler. So it always recalculates when the user activates the scroll animation (and no need anymore to hook it into the toggling class directly) :
duration = 600
Essential code :
scroll = function(c, a, b, i) {
if (modern) {
var present = Date.now(),
elapsed = present-initial,
progress = Math.min(elapsed/duration, 1);
c.scrollTop = a + (b - a) * progress;
if (progress < 1) requestAnimationFrame(function() {
scroll(c, a, b, i);
});
}
else {
i++; if (i > 30) return;
c.scrollTop = a + (b - a) / 30 * i;
setTimeout(function() {scroll(c, a, b, i)}, 20);
}
}
As a sidenote, it may appear to be animating quite sudden the first time when the button is clicked but that is because of Codepen. I suspect the focus is on the window with the script in it and not the content itself. Because of this that window has to 'wake up' first, a energy saving aspect of requestAnimationFrame
. When clicking anywhere else inside the content first, this will disappear. It should also not happen in a live environment. I might send them a message about it...