I've been dealing with this problem since days now and I hope somebody here can help me.
I'm trying to make a sticky navigation and a 100% height header (body and html are set to 100% height too). Basically the problem I have is that the sticky navigation only works well after the page is (re)loaded. However scrolling after having resized the browser's window makes the navigation either jump to early or to late to the fixed position at the very top.
I'd need to implement a resize event I guess, so that the calculation of the variable "navOffset" fires everytime the window is resized, right?
I tried many ways of inserting this into my code which are also explained in the link below, but I falied everytime.
I hope somebody can disclose this secret to me as I'm getting insane about this.
Thanks a lot and have a great week!
Sascha
Example of the effect I want to achieve:
http://html5-webdesign.berlin/
Tutorials, which didn't help me:
https://stackoverflow.com/…/jquery-combine-document-ready-an…
jQuery(document).ready(function() {
var navOffset = jQuery("nav").offset().top;
jQuery("nav").wrap('<div class="nav-placeholder"></div>');
jQuery(".nav-placeholder").height(jQuery("nav").outerHeight());
jQuery(window).scroll(function() {
var scrollPos = jQuery(window).scrollTop();
if (scrollPos >= navOffset) {
jQuery("nav").addClass("fixed");
} else {
jQuery("nav").removeClass("fixed");
}
});
});
Just copy your second function (which you should probably name) and add it to the window resize event:
jQuery(document).ready(function() {
var navOffset = jQuery("nav").offset().top;
jQuery("nav").wrap('<div class="nav-placeholder"></div>');
jQuery(".nav-placeholder").height(jQuery("nav").outerHeight());
function setPosition() {
var scrollPos = jQuery(window).scrollTop();
if (scrollPos >= navOffset) {
jQuery("nav").addClass("fixed");
} else {
jQuery("nav").removeClass("fixed");
}
}
jQuery(window).scroll(setPosition);
jQuery(window).resize(setPosition);
});
Related
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);
I have made a function wich runs on the computer very well. But on mobiles the position refreshes only when the scrolling stops. Its a known problem and i found answers but I didnt get it in my function working. Maybe one of you can help me.
my function:
$(window).scroll(function () {
if ($(window).scrollTop() >600) {
$('#logo').css('position', "fixed");
$('#logo').css('top', 0);
}
else if($(window).scrollTop() < 600) {
$('#logo').css('position', "relative");
$('#logo').css('top', 600)
}
});
and in the internet i found this which i should replace in my function:
$('body').on({
'touchmove': function(e) {
console.log($(this).scrollTop()); // Replace this with your code.
}
});
or this:
$('body').bind('touchmove', function(e) {
console.log($(this).scrollTop()); // Replace this with your code.
});
It would be nice if someone could rewrite my function so that it works smoothly in mobiles.
Edit
I explain shortly what this function do. When you load my page there is a blackscreen with a headline. Nothing else. when you scroll up the title should move up normaly until he reaches the top. when it reaches the top it gets the "position: fixed" attribute. when you scroll down it gets the "position: relative" attribute again. Nothing else should happen.
But on mobiles the text scrolls up until the scrolling stops (most of the time you scroll the text out of the screen) and pop up on the fixed position. But when it fixed everything is ok and it stands there.
The problem might be in the fixed position rather than in the scrollTop. Fixed positioned elements are not very mobile friendly.
Its behavior depends on the mobile device and OS.
More info: http://bradfrostweb.com/blog/mobile/fixed-position/
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.
I have a fixed div that I want to sit on top of a number of background images. The issue is that if this fixed div is taller than the window, it wont scroll, meaning content is lost. I've tried using max-height: 100% and y-overflow:scroll; but no luck.
I have figured a workaround using the following javascript:
<script>
$(window).scroll(function(){
var css = {};
if ($(window).scrollTop() > 120){
css = { top:'0'};
}
else {
css = {top:'120'};
}
$('#writtenContent').animate(css,{duration:200,queue:false});
});
</script>
Which moves it up, but this is not ideal for a number of reasons. Id like to either be able to know how much of the div is hidden, and then move up that amount, or have the fixed div scrollable. Ideally either of these should only happen if necessary i.e. if the div fits in the window, then no action taken.
Any ideas would be great!
===============UPDATE=================
Hi guys - here is a quick jsfiddle showing the type of thing. Its a stripped down version, but shows the problem Im having. If the window is resized to be smaller than the content holding div, we loose it.
Ok well first off, you said that it's a fixed div, which generally means position:fixed but then you say position:relative? What do those refer to? But it really should be scrolling. You said you tried y-overflow but of course that won't work. It's overflow-y with the y after. Try that again and see if it works. If it doesn't work then you will need to post all of the relevant code and styles so we can see what is going on.
Also it's somewhat hackish but try using max-height: with varying percentages less than 100% to see if it works even a little bit correctly.
If I'm understanding you correctly, this will work for you.
var win = window,
$writtenContent = $('#writtenContent'),
$writtenContentPosition;
function windowScrollMagic(){
$writtenContentPosition = $writtenContent.offset().top; // get elements distance from top
// if you've scrolled farther than the elements position:
if (win.scrollY > $writtenContentPosition) {
// do something, like animating $writtenContent to the win.scrollY coordinate
}
}
$(document).ready(function(){
$(win).scroll(){
windowScrollMagic();
});
});
Update in response to example jsfiddle:
var $win = $(window),
$winHeight,
$writtenContent = $('#writtenContent'),
$writtenContentPosition,
$writtenContentHeight,
$writtenContentBottomEdgePosition,
heightDifference;
function calculateHeights() {
$winHeight = $win.height();
$writtenContentPosition = $writtenContent.offset().top;
$writtenContentHeight = $writtenContent.height();
$writtenContentBottomEdgePosition = $writtenContentPosition + $writtenContentHeight;
heightDifference = $winHeight - $writtenContentBottomEdgePosition;
}
function windowResizeMagic() {
calculateHeights();
if (heightDifference < 0) {
$('#alert').html('Written Content is off screen by ' + heightDifference + 'px');
} else {
$('#alert').html('Written Content is not off screen');
}
}
$(document).ready(function(){
calculateHeights();
$win.resize(function(){
windowResizeMagic();
});
});
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.