Bram Vanroy
Bram Vanroy

Reputation: 28475

Window scroll, if-statements and animate not working correctly

Take a look at this jsFiddle.

When you scroll down a bit, a navbar should appear on the left. This works as it should. The problem arises when you scroll back to the very top. It should hide immediately, but it does not. Sometimes it hides after some seconds of delay and sometimes it does nothing. It doesn't hide either when you press the 'to top' button, which it should.

Any thoughts?

HTML

<nav id="menu-float">
    <ul>
        <li>List item 1</li>
        <li>List item 2</li>
        <li>List item 3</li>
    </ul>
    <div id="toTop">to top</div>
</nav>

CSS

nav#menu-float {
    position: fixed;
    left: 50%;
    margin-left: -300px;
    width: 120px;
    background: white;
    padding: 0.2em 0.4em;
    padding-bottom: 10px;
    border-radius: 8px;
    box-shadow: 0 3px 0px rgba(0, 0, 0, 0.1);
    top: 0;
    opacity: 0;
}

nav#menu-float div#toTop {
    background: #ffffff;
    background: -moz-linear-gradient(top,  #ffffff 0%, #ededed 100%);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff),   
color-stop(100%,#ededed));
    background: -webkit-linear-gradient(top,  #ffffff 0%,#ededed 100%);
    background: -o-linear-gradient(top,  #ffffff 0%,#ededed 100%);
    background: -ms-linear-gradient(top,  #ffffff 0%,#ededed 100%);
    background: linear-gradient(top,  #ffffff 0%,#ededed 100%);
    border: 1px #DDD solid;
    border-radius: 8px;
    box-shadow: 0 2px 2px rgba(0, 0, 0, 0.08);
    width: 50px;
    height: 20px;
    right: 5px;
    position: absolute;
    bottom: 5px;
    cursor: pointer;
    text-align: center;
}

JAVASCRIPT

// Only show side menu when x pixels from top and when window size allows it
function checkSize() {
    var floatMenu = $("nav#menu-float");

    if ($(window).width() > 560) {
            $(window).scroll(function() {
                if ($(document).scrollTop() > 100) {
                    floatMenu .animate({
                        opacity: 1,
                        top: "45px"
                    }, 800);
                }
                else {
                    floatMenu .animate({
                        opacity: 0,
                        top: "0px"
                    }, 800);
                }
            });
    }
    else {
        floatMenu .hide();
    }
}

checkSize();
$(window).resize(function() {
    checkSize();
});

// Back to top
$("div#toTop").click(function(e) {
    $("body,html").animate({
            scrollTop: 0
    }, 800);
});

Upvotes: 1

Views: 2904

Answers (2)

Darek Rossman
Darek Rossman

Reputation: 1323

You're queuing up tons of animations every time the scroll event fires, adding another 800ms to the overall time. You need to set some sort of flag to stop the scroll events from firing when the menu is showing, and remove the flag when scrolling goes back to the top to allow the menu to hide again.

The following just adds a check to see if the menu has a class of 'showing' and toggles the class on and off accordingly:

function checkSize() {
    var floatMenu = $("nav#menu-float");

    if ($(window).width() > 560) {
            $(window).scroll(function() {
                if ($(document).scrollTop() > 100 && !floatMenu.hasClass('showing')) {
                    floatMenu.addClass('showing').animate({
                        opacity: 1,
                        top: "45px"
                    }, 800);
                }
                else if ($(document).scrollTop() < 100 && floatMenu.hasClass('showing')) {
                    floatMenu.removeClass('showing').animate({
                        opacity: 0,
                        top: "0px"
                    }, 800);
                }
            });
    }
    else {
        floatMenu .hide();
    }
}

SEE MY FORK HERE

Upvotes: 1

sQVe
sQVe

Reputation: 2015

This should work:

$(function() {
    "use strict";
    function checkSize() {
        if ( $(window).width() > 560 ) {
            $(window).scroll(function() {
                if ( $(document).scrollTop() > 100 ) {
                    if ( $("nav#menu-float").css("opacity") === "0" ) {
                        $("nav#menu-float").animate({
                            opacity: 1,
                            top    : "45px"
                        }, 800);
                    }

                }
                else {
                    if ( $("nav#menu-float").css("opacity") === "1" ) {
                        $("nav#menu-float").animate({
                            opacity: 0,
                            top    : "0px"
                        }, 800);
                    }
                }
            });
        }
        else {
            $("nav#menu-float").hide();
        }
    }

    $(window).resize(checkSize);
    checkSize();

    $("div#toTop").click(function() {
        $("body,html").animate({
            scrollTop: 0
        }, 800);
    });
});

You have to check if the animation is done, otherwise you're going to animate the element again, again and again. if ( $("nav#menu-float").css("opacity") === "0" ) { checks if the opacity animation is done.

DEMO

Upvotes: 2

Related Questions