Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Nav bar fixed to top of browser window

Here is a code pen of what I have so far: http://codepen.io/anon/pen/tmwih

as you scroll down you will see that the nav bar eventually fixes itself to the top. I have it purposely scrolling out of view before it fixes itself to the top. But what I want to change is the immediate snap that it does to the top. Is there a way to have the nav bar slide down into view slowly instead of it snapping to the top the way it currently is?

You can annimate it with css ;)

9 Answers

So I added comments that explains what I'm doing, but I think the most unintuitive part is probably the following:

if (scrollTop > y_pos + height) {
      $navbar.addClass("navbar-fixed") .animate({ top: 0 });
    } else if (scrollTop <= y_pos) {
      $navbar.removeClass("navbar-fixed").clearQueue().animate({ top: "-48px" }, 0);
    }

I can't explain this in the comments of the script so I'll explain it here. The first part is pretty straightforward I think. If the top of the window hits the bottom of the navbar, then add the navbar-fixed class and then animate it's 'top' attribute to zero. The navbar-fixed class has "top: -48px". So, when the navbar-fixed class is added, the navbar is fixed just above the screen where you cannot see it. Then the animate function moves the 'top' attribute to 0, causing the navbar to be fixed right at the top of the window.

The second part, the "else if" part, is more complicated. It checks to see if the top of the window has hit the original position of the navbar. If so then it removes the navbar-fixed class, clear the queue and animates the "top" attribute back to -48px instantly. Let me explain.

The animate() function creates inline styles. So when the navbar element itself looks like this after the function runs:

<nav id="navbar" style="top: 0px">
...

So even if I remove the navbar-fixed class, the element still have a top attribute of 0. So when function runs again, we don't get that cool animation, it just snaps because the "top: 0px" is already there. So we have to run it back to -48px. That is why I use "animate({top: '-48px'}, 0);"

But here is the thing - I'm not exactly sure but I suspect animate() uses timing functions like "setTimeout." The way they work, you give them a function and it runs the function after a given period of time. Except it doesn't actually run the function - instead it adds it to a queue. If there are a bunch of other functions in the queue ahead of yours, then your function won't run for a while. So when we call animate(), it just gets added to a queue to run at some arbitrary time. The result is the navbar will animate, but you have to wait a while unless we clear the queue first. That is why I use clearQueue().

I'm sorry if this isn't as clear as it could be.

I've read a lot on javascript so I'm fairly comfortable with it, but I'm not experienced. It would be nice if somebody that was really experienced could comment on it and tell me if this is good practice or not.

The easiest way I can think to do this would be by adding the proper css transitions to your navbar-fixed class. However, that will only work in IE10 and later. For something as essential as displaying a nav element, I would shy away from using CSS Transitions.

I rewrote your pen here. I've been able to get it to work just as you'd like but for one thing: for some reason if you scroll down and up it works fine, but if you scroll back down again it does not play the animation.

I'm not sure what is causing this problem. My best guess is this is because my navbar-fixed class may be holding a "top" attribute of 0 the second time around. I'm not sure how to test this guess.

Nicholas Olsen -- When I try it on a web page I get an error in the console: "Uncaught TypeError: Cannot read property 'top' of undefined " from line 2

I'd have to see how you've applied the code but I can think of a few things that may be causing the error: Maybe you don't have anything in your markup with the ID #navbar. It could be that the selector in $() on line 1 is mistyped. Maybe the second line of the JS has $navbar.offset() misspelled.

Or it could be something else entirely.

edit: duplicate post by accident.

Ok, so I've fixed the issue I was having. It now works as I would like it to. I've never really messed with jQuery animations before so I can't say much about the quality of the code.

The one thing I'm doing that seems unintuitive is I'm using the animate() function to change inline styles because I can't find any other jQuery function that will do it. Check out the pen to see my changes.

I just had to include my scripts at the bottom of my html page and not in the head and it worked. Thanks for your help!

Nicholas Olsen Would you be willing to make comments on the jquery as to what the code is doing? I have gone through all the JavaScript and jQuery stuff on the site, but am still trying to wrap my head around it all.

Well thanks for taking the time to do this. This made plenty of sense. I am at a point where reading JavaScript is becoming more comfortable and understandable, I just cant seem to write more complex stuff yet. So thanks for taking the time to do this!