Change scrollTop offset - javascript

I am using bootstrap 3 and have a fullscreen hero unit at the top of my page, below that is my navigation. I have some js which allows my navbar to stick to be fixed at the top after you scroll past the full screen hero. Also some js for my smooth scrolling links.
The problem is the offset is different before you scroll past the full screen hero and after. But it works fine when you are past the jumbotron. I have tried a bunch of different things but I can seem to get this to work exactly.
Check out the fiddle here.
Here is my js for the smooth scrolling links:
$(document).ready(function() {
// navigation click actions
$('.scroll-link').on('click', function(event){
event.preventDefault();
var sectionID = $(this).attr("data-id");
scrollToID('#' + sectionID, 750);
});
// scroll to top action
$('.scroll-top').on('click', function(event) {
event.preventDefault();
$('html, body').animate({scrollTop:0}, 1200);
});
// mobile nav toggle
$('#nav-toggle').on('click', function (event) {
event.preventDefault();
$('#main-nav').toggleClass("open");
});
});
// scroll function
function scrollToID(id, speed){
var offSet = 95;
var targetOffset = $(id).offset().top - offSet;
var mainNav = $('#main-nav');
$('html,body').animate({scrollTop:targetOffset}, speed);
if (mainNav.hasClass("open")) {
mainNav.css("height", "1px").removeClass("in").addClass("collapse");
mainNav.removeClass("open");
}
}
if (typeof console === "undefined") {
console = {
log: function() { }
};
}
By changing var offSet = 95; I am able to adjust the offset but what would be the best way to use 180 before the navbar sticks to the top but 95 when it does?
Also here is the js I am using for my navbar:
$(function () {
/* $(".navbar-fixed-top").css({"top":$(".jumbotron").height()});
$(window).resize(function (e) {
$(".navbar-fixed-top").css({"top":$(".jumbotron").height()});
});*/
$(document).on( 'scroll', function(){
console.log('scroll top : ' + $(window).scrollTop());
if($(window).scrollTop()>=$(".jumbotron").height())
{
$(".navbar").addClass("navbar-fixed-top");
}
if($(window).scrollTop()<$(".jumbotron").height())
{
$(".navbar").removeClass("navbar-fixed-top");
}
});
});

Are you open to angular.js? I have a directive i use for this. As seen here.
I'll grab the plunker link for you. you might find the code helpful.
Essentially you need to create a ghost dom element to take the place of the menu when you pull it to an new layout position.
EDIT: Here it is
I won't suggest grabbing angular just for this. But you can use the basis of the events and logic to build your own solution.
This here is creating an element and placing in its place
$scope.spacer = $element.after(
'<div class="spacer" style="height:' + $element[0].clientHeight + 'px"> </div>').next();
then this element is removed when the menu is back to its static position.
Inspect the dom and watch how it changes, this will probably help you see the events and changes that need to take place.
EDIT 2 SOLUTION:
HERE is the concepts applied to your JSFiddle

It's not the best solution but by adding margin: 0 0 -100px 0; to your .navbaryou lose the spacing issue.
Also you're getting 22 console errors because of missing images. I'm not saying that this is causing any major problems but you would be better off losing them.

The problem is that when you have not scrolled past the hero, navigation is still part of the layout and pushes content bellow it a little lower. When you scroll past (either manually or via a script) the hero, navigation is removed and fix positioned. That makes everything which was bellow to "jump up" exactly of the navigation height.
That means if portfolio was 1000px from the top, on click you say: go 1000px from top; but then porfolio moves 100px up (as explained above) meaning it is now 900px from the top while the window scrolled 1000px as you asked.
When you have scrolled past the hero, nothing changes its position.

Related

fixed header not getting right classes on scroll after closing fixed sidebar

I have a fixed sidebar and a fixed header with scrollable content in the main section of the page. The header is to be triggered on the scroll to hide the top portion of itself on scroll down and then show itself on scroll up. The sidebar can be triggered to hide and show itself with a button. When this happens the header gains back the full width of the page until the button is pressed to bring back the sidebar. The page loads with the sidebar opened.
So far I've been able to get the sidebar to transition off and back on the page properly. I also have the header working as intended on page load. However the issue I'm having is with the transition, more so recognizing the changed classes when the sidebar closes. I believe my issue is with the scroll javascript not recognizing the sidebar is closed because when scrolling it applies the classes to the header for when the sidebar is open. To test this I added a class called SEEME123 which never shows.
Below is the javascript for scrolling changes.
var exploreOpen = $('#explore').hasClass('open');
var exploreClosed = $('#explore').hasClass('closed');
$(function () {
var position = $(window).scrollTop();
if (exploreOpen) {
$(window).scroll(function () {
var scroll = $(window).scrollTop();
if (scroll > position) {
$('#wrapper-site-header').removeClass('explore-open--header-full');
$('#wrapper-site-header').addClass('explore-open--header-reduced');
} else {
$('#wrapper-site-header').addClass('explore-open--header-full');
$('#wrapper-site-header').removeClass('explore-open--header-reduced');
}
position = scroll;
});
} if (exploreClosed) {
$(window).scroll(function () {
var scroll = $(window).scrollTop();
if (scroll > position) {
$('#wrapper-site-header').removeClass('explore-closed--header-full');
$('#wrapper-site-header').addClass('explore-closed--header-reduced');
$('#wrapper-site-header').addClass('SEEME123');
} else {
$('#wrapper-site-header').addClass('explore-closed--header-full');
$('#wrapper-site-header').removeClass('explore-closed--header-reduced');
}
position = scroll;
});
} else {}
});
The javascript for the sidebar function toggles the open and closed classes on the sidebar, along with removing or adding the appropriate header class.
I don't understand why this isn't working as intended and would like to know how to resolve the issue. I've searched around attempting to understand where I screwed up, or to find an example where the scroll function does X because of Y. I've also attempted the above without variables (ie..
$(function () {
var position = $(window).scrollTop();
if (('#explore').hasClass('open')) {
), and as separate functions.
Anyway, here is a jsfiddle in case I missed something. https://jsfiddle.net/at0yxo0m/
Thank you all for your help and advice.
EDIT: Additional information.
I do have an earlier version of this layout where the scroll function only changes the header area that works with closing the sidebar. However the animations were clunky in general, and worse on mobile. Also to get everything to work right I had to wrap elements more than I thought was needed. So it was my goal to streamline as much as I could while getting the desired result.

Positioning the top attribute of a element with jquery

I'm having an annoying issue trying to position the responsive navigation hamburger. I am using a plugin called responsive menu which creates the hamburger and uses absolute positioning.
I am trying to position the hamburger in the centre of the header at all times.
To achieve this I am using the following jQuery code.
However, the issue I have is when the hamburger is displayed and you scroll down the page and scroll back to the top of the page quickly. The hamburger does not position itself in the centre of the header. You need to scroll back down slightly for it to jump into place.
Any ideas how I can fix this please.. It's driving me crazy and I don't know jquery very well :(
Thank you for any advice in advance :)
Link to the site in question
$( window ).on("load resize scroll", function(e){
var headerHeight = $('nav').height()/2;
var iconHeight = $('#click-menu').height()/2;
var total = headerHeight - iconHeight;
if ($(window).scrollTop() >= 1) {
$('#click-menu').css('top', total);
}
else {
$('#click-menu').css('top', total);
}
});
It's hard for me to test and confirm this, but I believe the reason it's position is off when it hits the top is because the evaluation of $('nav').height()/2; happens immediately, but the header animates to size over 300 ms.
Although a bit hacky, I think you can solve the problem by adding a setTimeout
function setNavTop(){
var headerHeight = $('nav').height()/2;
var iconHeight = $('#click-menu').height()/2;
var total = headerHeight - iconHeight;
$('#click-menu').css('top', total);
}
$( window ).on("load resize scroll", function(e){
if ($(window).scrollTop() >= 1) {
setNavTop();
}
else {
setTimeout(setNavTop, 300); // wait for header to animate to size.
}
});
Since it has to delay for 300ms before adjusting the icon, its looks a bit glitchy. You can improve this by adding tweening the setTimeout. Not the most elegant, but it works
setNavTop();
setTimeout(setNavTop, 100);
setTimeout(setNavTop, 200);
setTimeout(setNavTop, 300);

One page scroll wrong offset with floating menu bar

I am having an issue. Im using a one page design for a friend with a fixed floating menu on the top. The problem I encounter is that when I click on a link it scrolls down but the offset is not right. Most the of time it scrolls down a little too much covering the content below the menu. What I am trying to achieve is that the scrolling stops at the div being exactly below my menu bar. The other issue is that somehow it wont scroll down when the space between two sections is too narrow. It tries but somehow only moves a few pixels then stops. I can imagine that both are related to the offset issue.
Im sorry, english is not my native language.
Here is what I got so far. A standard scrolling function with window.location.hash. The target are divs spread across the site.
$(document).ready(function () {
$('a[href^="#"]').on('click', function (e) {
e.preventDefault();
var target = this.hash;
var t = $(this.hash).offset().top;
$('.wrapper').animate({
scrollTop: t,
}, 1000, function () {
window.location.hash = target;
});
});
});
You can see an example of the problem live: http://rolfvohs.com/
What I tried so far was using the add.class function to bind the div with an extra padding when a link is clicked. It does work in a way but creates an awkward space. I also tried placing the divs at different locations but that does not fix the job either, just messes it up further.
I would appreciate some insight.
window.location.hash = target;
moves the scroll by default to the div position and you are setting offset top before the hash change so first its changes the offset after that it move to div location.
first try after removing the line "window.location.hash = target;" from the code
or
move the "window.location.hash = target;" out side and above the "$('.wrapper').animate({})" it will work .

fixed div while scrolling which moves other elements in a menu

I have some menu items on the right hand side of my website that are: -
Basket Summary
Best Sellers
Quick Links
etc
I want the basket summary to follow down the page as the page is scrolled, I know how to this using position: fixed, but I need it to also move the other elements out of the way otherwise it will just overlap them.
I was looking at this: jsfiddle which would do the job and works but obviously thats only on button click, I would need to adapt this to scroll via jQuery.
I have read many tutorials for floated fixed divs but they are all for one div and don't have any other divs to interact with.
Any ideas if possible and/or how to do it?
Code from js fiddle as follows: -
$(function() {
$('.upButton').click(function(e){
var $parent = $('.highlight').closest('.box');
$parent.insertBefore($parent.prev());
});
$('.downButton').click(function(e){
var $parent = $('.highlight').closest('.box');
$parent.insertAfter($parent.next());
});
});
Is this what you're looking for?: http://jsfiddle.net/cmontgomery/YVh4q/
essentially, whenever the window scrolls check to see if your section is in the visible area and if not, adjust accordingly:
$(window).scroll(function () {
var mover = $("#sidebar .quick-links");
if($(window).scrollTop() === 0) {
//console.log("to top");
mover.prependTo("#sidebar");
} else if(!isFullyInViewableArea(mover)) {
var parent = mover.closest('.section');
if(isBelowViewableArea(mover)) {
//console.log("moving up");
parent.insertBefore(parent.prev());
} else {
//console.log("moving down");
parent.insertAfter(parent.next());
}
}
});
I must admit, this solution is not the best user experience, i.e. it jumps instead of scrolling smoothly. If it were me I would put the movable section as the last item in the right column and move that down the page with absolute positioning so it follows the top of the view-able area exactly.
Use this
Drag & Drop is best.
Greetings.

Keeping sidebar in viewport, problem with scrolling

I've got a solution for keeping a sidebar in the viewport as you scroll up and down the page. Problem comes in when the sidebar is longer than the content area, and you keep scrolling you get this jittering effect as the sidebar keeps pushing the footer down.
I've got an example of this setup in jsFiddle: http://jsfiddle.net/U9F7w/2/ (full screen: http://jsfiddle.net/U9F7w/2/embedded/result/ )
My question is, is there a way to make the sidebar stop once it touches the bottom/footer area?
I've read some solutions about setting the sidebar to absolute, unfortunately it's an existing site and changing the position didn't work and messed with a lot of the existing page elements.
Here's the jQuery/js I'm working with:
// set the offset
var sidebarOffset = $(".sidebar").offset();
var sidebarPadding = 15;
// when the window scrolls, keep sidebar in view
$(window).scroll(function() {
if ($(window).scrollTop() > sidebarOffset.top) {
$(".sidebar").stop().animate({marginTop: $(window).scrollTop() - sidebarOffset.top + sidebarPadding });
}
else {
$(".sidebar").stop().animate({marginTop: 0});
};
});
edit
One thing I thought about was (not sure if this is possible) to detect if the bottom of one div was lower than the bottom of another, stop the scrolling. Is there a way to detect if the bottom of one div is lower than the other?
Check if the sidebar's height is greater then that of the content:
var ct = $(".content");
var sb = $(".sidebar");
var sbOffsetTop = sb.offset().top;
var sbPadding = 15;
$(window).scroll(function() {
if (sb.height() < ct.height()) {
if ($(window).scrollTop() > sbOffsetTop) {
sb.stop().animate({top: $(window).scrollTop() - sbOffsetTop + sbPadding });
}
else {
sb.stop().animate({top: 0});
};
};
});
See demo fiddle with large content and demo fiddle with large sidebar.
And I don't know why exactly, I would use top in conjunction with position: relative, but marginTop works also fine.

Categories

Resources