Search code examples
javascriptjquerycssscrollfixed

Wink/blink issue with fixed menu on y-scroll


I wish a div element of my right menu to fit the bottom of the header menu while y-scrolling to bottom and then stay fixed. And while y-scrolling to top, to stay relative to his previous element.

This is not easy to explain, so please have a look to the following : fiddle

HTML

<div id="main">
    <div id="menu">Fixed Menu</div>
    <div id="container">
        <div id="content">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit....
        </div>
        <div id="right_menu">
            <div id="items">
                <!-- Variable number of items !-->
                &bull; Some items<br/>
                &bull; Some items<br/>
                &bull; Some items<br/>
                &bull; Some items 
            </div>
            <div id="fixed_items">
                <!-- Items to be fixed to top menu by scrolling !-->
                &bull; Fixed scroll items<br/>
                &bull; Fixed scroll items<br/>
                &bull; Fixed scroll items
                <input type="text" id="test"/>
            </div>
       </div>
    </div>
</div>

CSS

#main {
    position:relative;
    height:2000px;
    overflow-y:scroll;
    background:#EDEDED;}
#menu {
    position:fixed;
    z-index:10;
    width:100%;
    line-height:40px;
    background:#555555;
    color:#EDEDED;
    padding-left:10px;}
#container {
    display:table;
    width:100%;
    margin-top:40px;}
#content {
    display:table-cell;
    padding:10px;
    text-align:justify;}
#right_menu {
    display:table-cell;
    width:200px;}
#items, #fixed_items {
    position:relative;
    z-index:9;
    width:160px;
    padding:10px;
    border-bottom:4px solid #555555;
    background:#CCCCCC;}
input {width:100px;}

JS

$(document).ready(function(){
    $(window).scroll(function(){fix_items();});
});
function fix_items()
{
    var windowPos=$(window).scrollTop(),
        bloc=$('#fixed_items'),
        blocPos=bloc.position(),
        newPos=windowPos-blocPos.top+40;
    if(newPos>0)
        bloc.css({'position':'fixed','top':'40px'});        
    else if (newPos<=0)
        bloc.css({'position':'relative','top':'0px'});
    $('#test').val(blocPos.top+'/'+windowPos);
}

At the bigining, I was using some stop().animate({"come CSS"}) btw the easing was really annoying... and animate({'position':'fixed'}) doesn't seems to work (tested with chrome).

Without :

else if (newPos<=0)
        bloc.css({'position':'relative','top':'0px'});

It works like a charm, but the #fixed_item can't fit again to #items. I guess that the problem is here and I can't find the solution.

Any idea to do the job without this ugly effect ?


Solution

  • It's be better to test the position of the previous element, than the element with a fixed scroll (because the fixed element position seems to jump...).

    With the following, you'll have the ugly effect just one time :

    function fix_items()
    {
        var windowPos=$(window).scrollTop(),
            bloc=$('#fixed_items'),
            prev=$('#items'),
            prevPos=prev.position(),
            header=$('#menu'),
            newPos=windowPos - (prevPos.top + prev.height() - 16);
        if(newPos>=0)
            bloc.css({'position':'fixed','top':'40px'});        
        else if (newPos<0)
            bloc.css({'position':'relative','top':'0px'});
    }
    

    Fiddle