I am using following code to make a menu sticky when the window is scrolled down. It works fine if the window height is enough to scroll down the full header area, but it it creates problem is the height is just close enough to scroll, in that case it starts flashing and does not let scroll.
Here is the demo of the problem, refresh couple of times and try to scroll down. I have set the body height to 622px to reproduce the problem:
http://jsbin.com/ipEROYO/1
Here's the code I'm trying:
$(document).ready(function() {
var stickyNavTop = $('.nav').offset().top;
var stickyNav = function(){
var scrollTop = $(window).scrollTop();
if (scrollTop > stickyNavTop) {
$('.nav').addClass('sticky');
} else {
$('.nav').removeClass('sticky');
}
};
stickyNav();
$(window).scroll(function() {
stickyNav();
});
});
CSS:
.sticky {
position: fixed;
width: 100%;
left: 0;
top: 0;
z-index: 100;
border-top: 0;
}
It's because when you are setting the navigation div to position:fixed you are shortening the length of the document (by the height of that div), which then causes the scroll bar to go away, which causes the scrollTop() value to be 0 which causes the .nav div to be position:static and it is an endless cycle if you keep scrolling down.
Here's my quick solution:
$(document).ready(function() {
var height = $('.nav').outerHeight();
$(window).scroll(function() {
if($(this).scrollTop() > height)
{
$('.nav').css('position','fixed');
$('body').css('padding-bottom',height+'px');
}
else if($(this).scrollTop() <= height)
{
$('.nav').css('position','static');
$('body').css('padding-bottom','0');
}
});
$(window).scroll();
});
Just modified the JSbin. Check it out. You were really close, just doing more than you needed to like setting the sticky class on load of the page rather than when the function first runs. Let me know if this helps.
try that
$(window).scroll(function () {
var scroll_top = $(this).scrollTop();
if (scroll_top > 66) {//height of header
$('.nav').addClass('sticky');
} else {
$('.nav').removeClass('sticky');
}
});
Strongly recommend a CSS only solution for this layout. No one seems to know what to call this method, so I've been referring to it as the absolute stretch technique, but in my experience it works beautifully across mobile devices and PC's including all major browsers except IE6 and below. There is some discussion of it here.
body, .header, .nav, .mainContent{
position: absolute;
top: 0;
left: 0;
right: 0;
}
body, .mainContent {
bottom: 0;
}
.header{
height: 120px;
}
.nav{
height: 70px;
top: 120px;
}
.mainContent{
top: 190px;
overflow: auto;
}
You'll find you can get very robust, concise, well organized layouts in this manner, and fixed headers, footers and sidebars follow very easily.
Related
I'm currently using bootstrap's navbar with built-in scrollspy function in an one page layout. (like in this example: http://blackrockdigital.github.io/startbootstrap-scrolling-nav/)
I want to place the navbar at the bottom in the #intro section and to become fixed at the top when scrolling down.
Question:
How to prevent the navbar from jumping up and down (both when scrolling and when clicking a navigation element)?
//////////////////////////////////////////////////////
Solution:
I solved the problem by adding some CSS to the demo mentioned above:
.navbar {
position: absolute;
bottom: 0;
width: 100%;
height: 50px;
margin: 0;
}
.navbar-fixed-top {
position: fixed;
right: 0;
left: 0;
top: 0;
z-index: 1030;
}
and changed the jQuery code to:
$(document).ready(function(){
$(window).bind('scroll', function() {
var navHeight = $( window ).height() - 50;
if ($(window).scrollTop() > navHeight) {
$('.navbar').addClass('navbar-fixed-top');
}
else {
$('.navbar').removeClass('navbar-fixed-top');
}
});
});
For demo look JSFiddle: https://jsfiddle.net/90jbhe54/
Now it works nice and fluently.
I want mynavbar to be transparent when the page is scrolled to the top, however when the user scrolls I would like it to be made opaque. I tried this with javascript, but something still isn't working.
http://jsfiddle.net/6A6qy/
function myFunction() {
if ($(window).scrollTop() < 50) {
document.getElementById("masthead").style.opacity = "0.5";
}
}
#masthead {
position: fixed;
top: 0;
left: 0;
z-index: 9999;
width: 100%;
height: 50px;
background-color: #00a087;
opacity: 1;
}
#container {
background-color: blue;
height: 1000px;
display: block;
margin-top: -50px;
}
<body onload="myFunction()">
<nav id="masthead">
<!-- Fixed navigation bar content -->
</nav>
<div id="container"></div>
</body>
How about this:
JS:
// listen for scroll
$(window).scroll( function() {
// apply css classes based on the situation
if ($(".masthead").offset().top > 100) {
$(".masthead").addClass("navbar-scrolled");
} else {
$(".masthead").removeClass("navbar-scrolled");
}
}
CSS:
.navbar-scrolled {
/* some css for navbar when scrolled */
}
JSFiddle example:
http://jsfiddle.net/8ruwnaam/
And then of course you could add some optimization to not apply the classes all the time if they are already there. But it works quite fine without such things as well.
Additional things:
The first version of this answer and your question use IDs for styling, which is not really a good idea according to a lot of people. Styling IDs goes against the DRY principles, and causes all these funny little problems when you forget to think about CSS specificity. IDs are quite alright for a lot of things when it comes to the logic in the JS or something, but try to use classes for styling.
You should create an .opaque css class and attach it based on actively scrolling or if scrollTop is < 50:
.opaque {
opacity: 0.5;
}
Then attach that class on('scroll') or at scrollTop (this is using the debounce plugin):
function myFunction() {
var $masthead = $('#masthead')
, $window = $(window);
// currently scrolling
$window.scroll($.debounce( 250, true, function(){
$masthead.addClass('opaque');
}));
// done scrolling
$window.scroll($.debounce( 250, function(){
// if at the top, add or keep opaque class
if($(this).scrollTop() < 50) {
if(!$masthead.hasClass('opaque')) {
$masthead.addClass('opaque');
}
} else {
$masthead.removeClass('opaque');
}
}));
}
You need to set it to be transparent by default (as it will be on the top) like that
#masthead {
position: fixed;
top: 0;
left: 0;
z-index: 9999;
width: 100%;
height: 50px;
background-color: #00a087;
opacity: 0.5; /*edited the opacity to be 50% by default*/
}
then use this script to achieve your needs:
$(document).ready(function () {
$(window).scroll(function(){
var ScrollTop = parseInt($(window).scrollTop());
if (ScrollTop < 100) {
document.getElementById("masthead").style.opacity = "0.5";
} else {
document.getElementById("masthead").style.opacity = "1";
}
});
});
I have a header on a website that is fixed 20px from the top of the page.
However, I want this to catch the top of the page when scrolling and become fixed to the top of the screen once the user has scrolled that 20px down.
CSS
#header{
padding: 0px 0px 0px 0px;
background: url(../images/header-fill2.jpg) repeat-x top;
position: fixed;
height: 60px;
width: 100%;
top: 20px;
z-index: 5000;
}
I imagine some form of JavaScript is required but have little to no JavaScript experience, so any help would be greatly appreciated.
Just listen for the scroll event and read the value of $(window).scrollTop() and set the top according to that.
Something like:
$(window).on('scroll', function() {
$('#header').css('top', $(window).scrollTop() > 20 ? '0px' : '20px');
});
Example on jsFiddle
The scroll event tells you when the window scrolls. Then, use the scrollTop to find out how much closer to 0 to go:
$(window).on("scroll", function() {
$("#header").css("top", Math.max(0, 20 - $(window).scrollTop()));
});
Live Example
Or to avoid constantly re-creating objects:
(function() {
var $wnd = $(window),
$header = $("#header");
$wnd.on("scroll", function() {
$header.css("top", Math.max(0, 20 - $wnd.scrollTop()));
});
})();
Live Example
Thats how I do that with jQuery.
The position is also cached, for performance reasons:
Here is a fiddle:
http://jsfiddle.net/StephanWagner/u3yrS/
$(document).ready(function() {
var cfixed_nav = false, wscroll;
var setScroll = function() {
wscroll = $(window).scrollTop();
var fixed_nav = wscroll > 20; // Set pixel amount here
if (fixed_nav != cfixed_nav) {
$('body')[fixed_nav ? 'addClass' : 'removeClass']('fixed');
cfixed_nav = fixed_nav;
}
};
setScroll();
$(document).scroll(setScroll);
});
With CSS you set the fixed position:
.fixed #header {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100%
}
Also remember, that when the header gets the fixed position, those 20px of the header are missing. So you can add a body padding for example:
.fixed {
padding-top: 20px;
}
Or you add an element with 20 Pixel height and swap display none / block depending on the .fixed class in the body
I have a "sticky" sidebar contact form with jQuery, which turns to fixed-positioned div when page is scrolled down. My problem is that it overlaps the footer when scrolled down all the way. Is there a way where I could set it not to scroll down any further once its bottom margin starts hitting the footer? I'm not sure how I would detect that event, if at all possible, because it's a responsive site and footer's height varies.
CSS:
.sticky {
margin-top: 38px;
max-width: 300px;
padding-top: 20px;
z-index: 0;
}
jQuery:
jQuery(function(){ // document ready
if (!!jQuery('.sticky').offset()) { // make sure ".sticky" element exists
var stickyTop = jQuery('.sticky').offset().top; // returns number
jQuery(window).scroll(function(){ // scroll event
var windowTop = jQuery(window).scrollTop(); // returns number
if (stickyTop < windowTop){
jQuery('.sticky').css({ position: 'fixed', top: 0 });
}
else {
jQuery('.sticky').css('position','static');
}
});
}
Thanks all in advance.
I'm trying to create a basic sticky header.
The header contains 2 parts: top and main. When page is scrolled down, i want to keep only the .main sticky (so that the .top becomes invisible).
I'm trying following code, but it is jerky and if the content has a specific height, it does not let scroll, starts jumping. I have captured video to illustrate the problem. Please see:
http://www.screenr.com/Z89H
Here's the demo:
http://jsfiddle.net/M33g4/
(you might not see the issue because of different screen height, in that case drag the results window to set its height about 535px).
HTML:
<header>
<div class="top"></div>
<div class="main"></div>
</header>
<section>
</section>
jQuery:
$(window).scroll(function () {
var height = $('header').outerHeight();
if($(this).scrollTop() > height){
$('header').addClass('sticky');
}else{
$('header').removeClass('sticky');
}
});
I'm sure you will have fixed this by now but after encountering the same issue I came up with a solution:
The issue was caused by the document size not having enough leeway beneath the fold to fit the height of the overall header. This meant that if a visitor tried to scroll down, the sticky part of the header will become fixed, but immediately unfix itself.I believe it may be the bounce-back effect that causes the problem but I haven't tested to verify this.
In short, I fixed it by adding simple check to ensure that there is more than enough space beneath the fold by comparing the height of the body and the height of the window. i.e body height minus window height must be greater than the total header height. Here's the code that worked in my instance:
// Sticky sub navbar
var sub_nav_height = $('#sub-nav').outerHeight();
var total_height = $('#main-head').outerHeight();
var header_height = total_height - sub_nav_height;
var content_height;
var y;
$(window).scroll(function() {
// Only make sticky if window is large enough not to cause jumping issue
content_height = $('body').height() - $(window).height();
if(content_height > total_height) {
y = $(this).scrollTop();
if($(this).scrollTop() > header_height) {
$('#sub-nav').addClass('fixed');
} else {
$('#sub-nav').removeClass('fixed');
}
}
});
There are two caveats which I decided were absolutely fine for my scenario. The first is that an extra calculation has been added every time the scroll event is triggered, but this hasn't caused me any performance issues. The second is that the sticky header functionality is simply disabled when a vistor's window is a problematic size, but again I had no qualms with this as the navbar could still just about be seen.
Check this
http://jsfiddle.net/M33g4/3/
JS
$(window).scroll(function () {
var height = $('.top').height();
if($(this).scrollTop() > height){
$('.top').hide();
$('header').addClass('sticky');
}else{
$('.top').show();
$('header').removeClass('sticky');
}
});
CSS
*{
margin: 0;
padding: 0;
}
header{
width: 100%;
}
.top{
height: 50px;
background: blue;
}
.main{
height: 70px;
background: green;
}
section{
height: 560px;
background: yellow;
}
.sticky{
position: fixed;
width: 100%;
}
You should target to the top but not to whole header demo
$(window).scroll(function () {
var height = $('header .top').outerHeight();
if($(this).scrollTop() > height){
$('header').addClass('sticky');
}else{
$('header').removeClass('sticky');
}
});
http://jsfiddle.net/M33g4/1/
$(window).scroll(function () {
var height = $('.top').outerHeight();
if($(this).scrollTop() > height){
$('header').addClass('sticky');
}else{
$('header').removeClass('sticky');
}
});
guess you got the wrong height.
Updated:
The blinking issue is caused by height changing (due to position: fixed)
check this one: http://jsfiddle.net/M33g4/6/
$(window).scroll(function () {
var height = $('.top').outerHeight();
if($(this).scrollTop() > height){
if($('.main.sticky').length == 0) {
$('header').append(
$('.main').clone().addClass('sticky'));
}
}else{
$('.main.sticky').remove();
}
});
and stick .main only:
.sticky{
position: fixed;
width: 100%;
top: 0;
}
This works for me:
Set the height variable to 30:
$(window).scroll(function () {
var height = 30;
if($(this).scrollTop() >= height){
$('header').addClass('sticky');
}else{
$('header').removeClass('sticky');
}
});
and change the css for the sticky class to the following:
.sticky{
position: fixed;
width: 100%;
top: -30px;
left: 0;
}
Top is -30 instead of -40. Works for me!
Check how the content in this demo snaps to the top, under the header, but not visible. You might want to resize the Results window to about 500px. Is there a solution to this please?
$(window).scroll(function () {
var height = $('.top').outerHeight();
if($(this).scrollTop() > height){
$('header').addClass('sticky');
}else{
$('header').removeClass('sticky');
}
});