3

I am working on a sticky nav for a website currently, and I am running into a few problems, when the nav becomes position:fixed it seems to jump and it looks "clunky", here is a fiddle of what I am trying to do,

http://jsfiddle.net/DKtLR/

Ideally the outcome would be the user scrolls and the nav is not in a fixed position until it is scrolled out of the viewport it then becomes fixed and and slides back into view.

Udders
  • 6,914
  • 24
  • 102
  • 194
  • 2
    how will this work in this example? the menu is already at the top of the page, there isn't any case where the user's viewport is above the menu. this will probably work better if the menu is not at the top of the page. – Rodik Jul 18 '12 at 09:40
  • I would also say: if it's already on top of the page leave it there and fix it right away. If it's not, scroll it until it hits the ceiling and than fix it. – insertusernamehere Jul 18 '12 at 09:47
  • Thats what I am trying to do, but it feels like there is a jump when it becomes fixed – Udders Jul 18 '12 at 09:48
  • 1
    You should take a look at [this one](http://code.google.com/p/sticky-panel/). – morgi Jul 18 '12 at 09:48

4 Answers4

2

Since you only want it to become fixed when it is completely out of viewport, then slide in, just modify the top property and then animate it back into view. See this fiddle for a working example.

UPDATE

This updated fiddle should work better, as it only applies the behaviour if not already applied, and completely removes dynamic styles when returning to normal 'static' position.

Note there is still a flicker when scrolling back up - this is because the nav 'jumps' from its fixed position back to its static position. This can easily be resolved using a similar technique to the animation above.

chrisfrancis27
  • 4,516
  • 1
  • 24
  • 32
  • 1
    is there a way to stop the nav flickering when I scroll down the page? Thanks for the example it is awesome! – Udders Jul 18 '12 at 10:32
  • I don't see any flickering in Chrome, what browser are you using? – chrisfrancis27 Jul 18 '12 at 10:34
  • chrome on mac, it filckers when implemented on my localhost version of the site. Definatly a flicker when the page is long and scrolling is prolonged. http://jsfiddle.net/D8V7b/2/ – Udders Jul 18 '12 at 10:37
  • This is a similar solution to mine, although it doesn't really switch display based on menu height but rather on some predefined dimension. – Robert Koritnik Jul 18 '12 at 13:09
  • Yes, for the sake of brevity I used the existing dimension, but of course you could very easily detect the header height and use that instead. – chrisfrancis27 Jul 18 '12 at 13:48
  • @sico87 Did this work for you? Interested to see what you used in the end. – chrisfrancis27 Jul 19 '12 at 10:43
1

You can simply use the StickyScroller jquery plugin: http://vertstudios.com/blog/jquery-sticky-scroller-position-fixed-plugin/

Aidas Bendoraitis
  • 3,965
  • 1
  • 30
  • 45
0

I made this alternative solution based on this solution. Based on the setInterval function (see also console log).

var interval_id = false;
var curOffset, oldOffset;
var altmenu;
$(document).ready(function(){
    altmenu = $('.top-nav')[0].cloneNode(true);
    altmenu.style.position = 'absolute';
    altmenu.style.display = 'none';
    document.body.appendChild(altmenu);
    oldOffset = $(window).scrollTop();
    $(document).bind('scroll',function(){
        if (interval_id) {
            return;
        }
        //altmenu.style.display = 'none'; // optional
        interval_id = setInterval(function() {
            curOffset = $(window).scrollTop();
            if(curOffset == oldOffset) {
                console.log('scrolling stopped',curOffset);
                clearInterval(interval_id);
                interval_id = false;
                if (curOffset>120) {
                    altmenu.style.display = 'block';
                } else {
                    altmenu.style.display = 'none';
                }
                $(altmenu).css({
                    top: (curOffset-120)+'px'
                }).animate({
                    top: (curOffset)+'px'
                }, 500);
            }
            oldOffset = curOffset;
        }, 500); //setInterval
    });//scroll
});//ready

Test script and jsfiddle are here.

Community
  • 1
  • 1
Stano
  • 8,749
  • 6
  • 30
  • 44
0

At top and then fixed with animation so it's not clunky

This might be the solution you're looking for because it provides the fixed menu bar when scrolled out of the view, but when it switches from top to fixed, it does a slide-down animation, so it doesn't feel as you described it clunky.

HTML I've used in the example (simplified):

<div id="menu">
    <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
        ...
    </ul>
</div>
<div id="content" />

CSS is of course simple (only relevant styles)

#menu {
    position: absolute;
    width: 100%;
}
#menu.out {
    position: fixed;
}
#menu ul {
    margin: 0;
    list-style: none;
}
#menu ul li {
    display: inline-block;
}

And the script that does it and does so quickly (so it performs as fast as possible because the slowest part is the call to browser native getBoundingClientRect() function which means it's still fast, very fast):

$(function() {

    // save element references for faster execution
    var menu = $("#menu");
    var ul = menu.find("ul");
    var content = $("#content")[0];

    // get menu actual height
    var menuHeight = menu[0].getBoundingClientRect().bottom;

    // detect whether menu is scrolled out
    var inView= true;

    $(document).scroll(function(evt) {
        evt.preventDefault();

        var top = content.getBoundingClientRect().top;
        var nextInView = (top + menuHeight) > 0;

        // did state change so we have to change menu positioning
        if (inView ^ nextInView)
        {
            inView = nextInView;
            if (inView)
            {
                menu.removeClass("out");
            }
            else
            {
                menu.addClass("out");
                ul.hide().slideDown("fast");
            }
        }
    });

});

And this is it. You could also tweak the animation from slideDown() to slide in by animating top style property while you know exactly how many pixels above the view port you have to put the menu before the animation.

When you scroll the page and menu gets out of the view, it switches it to fixed position and scrolls the menu down so it dosesn't just jump in view but rather smoothly gets back in.

Robert Koritnik
  • 103,639
  • 52
  • 277
  • 404