Scroll to Top Animation with jQuery & CSS

An in-page link for scrolling the page to the top, is nothing new. Many years ago it was quite popular to put one in footer. Then they disappeared from most sites for a long time, and now (or maybe a year back or so) they’re gaining popularity again. Sometimes you see scroll to top links positioned at fixed locations to the bottom of the viewport as you scroll down a page, and sometimes as conventional links within – or just above – the footer.

The reasons for the return of the scroll to top -link is likely responsive design and smartphones, since a web page (if responsive design is used) viewed on a smartphone’s relatively small screen usually means you have to scroll/swipe vertically a long way to get back to the top. Perhaps also the increased support for the postion:fixed in most browsers is a reason.

Whatever the reasons, I belive a link for scrolling to the top is useful. Especially when browsing on smartphones. Below is the HTML, CSS and Javascript for a scroll to top animation, but before you dive into that you might wanna check out the demo to see it in action.

Structure – HTML for this Example

<body id="page-top">
    <div id="content">

      <div class="inner">

      ... a page to demonstrate a scroll to top animation

    <div id="footer">
      <div class="inner">
        <p id="copyright-and-such">

          I'm a footer

        <a id="scroll-top" href="#page-top">Top</a>

Function – Javascript for this Example

For the animation, and to make the scroll to top link initially hidden and display only when the page is scrolled, I use this jQuery function.

function addScrollTopAnimation() {
   var $scrolltop_link = $('#scroll-top');

   $scrolltop_link.on( 'click' ,  function ( ev ) {
      $( 'html, body' ).animate( {
         scrollTop: 0
      }, 700 );
   // Hides the link initially
   .data('hidden', 1).hide(); 
   var scroll_event_fired = false;
   $(window).on('scroll', function() {
      scroll_event_fired = true;
   Checks every 300 ms if a scroll event has been fired.
   setInterval( function() {
      if( scroll_event_fired ) {
         Stop code below from being executed until the next scroll event. 
         scroll_event_fired = false; 
         var is_hidden =  $'hidden'); 
         Display the scroll top link when the page is scrolled 
         down the height of half a viewport from top,  Hide it otherwise. 
         if ( $( this ).scrollTop()  >  $( this ).height() / 2 ) {
            if( is_hidden ) {
               $scrolltop_link.fadeIn(600).data('hidden', 0);
         else {
            if( !is_hidden ) {
               $scrolltop_link.slideUp().data('hidden', 1);
   }, 300); 

The setInterval section in the function above is used to prevent scrolling from becoming sluggish in some browsers. Haven’t noticed any problem with this when I tried without setInterval, but better safe than sorry. You can check out John Resig’s article on this matter.

Style – CSS for this Example

Everything except the width of the content div (#content) and the fixed position of the scroll top link (and the media query that changes its position), doesn’t really matter for the core functionality.

#content {
  max-width: 40em; 
  margin: 0 auto; 
  text-shadow:0 1px 0 #fdfdfd;

.inner {
  padding:0 4%;

#footer {
  border-top:1px solid #ccc;

#footer .inner {

*Footer left content 
#footer  #copyright-and-such {
  text-shadow:-1px -1px #111;

* Scroll to top link inside footer, 
* but fixed relative to viewport
#footer #scroll-top {
  /* On top of everything */
  padding:0.15em 0.5em;
  border:1px solid transparent;

* Up Arrow for the scroll top link 
#footer #scroll-top:after {
  width: 0;
  height: 0;
  border-left: 0.3em solid transparent;
  border-right:  0.3em solid transparent;
  border-bottom:  0.3em solid #fefefe;

Avoid having the Scroll to Top Link Overlap Page Content

To prevent the content from being overlapped by the scroll top link on smaller screens I’ve used a max-width media query to change its position to static when the viewport width becomes narrower than 55em.

* When the viewport is 55em (15em wider
* than the 40em max-width for #content) 
* it gets a static postion to not 
* overlap the content area 
@media screen and (max-width: 55em) {
  #footer #scroll-top {

30 Responses

  1. Joey says:

    I’m gonna use it for a client project.
    Thank you, keep up the good work!

  2. Mike says:

    Why do you use data hidden?

    var is_hidden =  $'hidden'); 
    • Martin Carlsson says:

      Not sure if it’s needed, but the idea was that calling fadeIn or slideUp regardless of whether the scroll top link is visible or not would be unnecessary. And instead of checking the scroll top link’s visibility with something like $“: visible”) while fadeIn or slideUp is running, I check whether its been instructed to be hidden or not on the previous scroll event.

  3. Kevin says:

    You could make the scroll top button a little transparent using CSS instead of removing position fixed with a media query.
    That way mobile visitors can use it even when they’re not at the bottom of the page.

    • I’ve seen that on some sites, but personally I prefer to do it this way since some content that get overlapped on smaller screens might be clickable (such as links).
      Having put transparency on the scroll to top -link makes that content visible, but not clickable without first scrolling past that area.

  4. my site is underconstruction and i want to add the ” scroll to Top animation” in my pages….how?

    • You can download the demo files and upload the Javascript and CSS files to your server.

      Or you can copy what you need into your existing files. Putting the CSS code to the bottom of your main style sheet perhaps.

      Good luck!

  5. Daniel says:


    I have done everything but seam to have something wrong, the back to top btn is always visible and when you click the link it jumps to the top and dont scroll?

    any help would be great, you have my email address.


  6. Reg says:

    Is there a way to specifically target a scroll point in the browser instead of half the viewport height? Say a pixel or em value

  7. Fran says:

    I can’t get the widget to hide initially, and it scrolls instantaneously, not quite to the top. I have no idea what I’m doing. I’m using Sandvox. Can anyone help?

  8. Hi Martin,

    Your Tuto is one of the best I’ve found on the net about this functionnality : safe, responsive, clean….Many thanks !

    Would you mind to give us a hint to integrate it in WordPress : I’ve fully customize it, it’s display correctly on my pages, but whatever I’m doing, the script is not considered at all 🙁

    I’ve try to place the .js script in functions.php (enqueue method), on the header, next to the html code (to be sure it works)…but nothing…The link is not animated.

    Thanks for your help !

    • Thank you Fabrice.
      About your site, maybe you’ve forgot to call addScrollTopAnimation()? Check out the .js source of the demo.

      …or maybe the script runs before the DOM is fully loaded.

      Also, check the source of your page to make sure you see the script inclusion.

      Do you have a link to your site?

      • Great !

        Your message gave me a new idea !
        I add the script on the footer, and it works (it unfortunately does not work on the header or functions.php file).

        Thanks for your very quick and kindful help.
        PS : the link to my site is just under my name

  9. Conor says:

    Hi, i am a novice at coding – would this work on a Cargo Collective website. And if so, how would i go about doing this?



  10. Bill says:

    I’m trying to get this to work with SharePoint 2010 and having no luck at all. I have a custom masterpage that is used on every single page in my web application. In my masterpage I have a reference to a custom CSS file I’m using and also have a reference to a custom JQuery file I’m using. I’m using other CSS and JQuery without issue, but I can’t seem to figure this one out. What do I need to put in my masterpage and what do I need to put in the default pages HTML to get this to work? I got this button to always show up, but clicking it does nothing?

  11. Bridgette says:

    Hello, I enjoy reading through your article post.

    I wanted to write a little comment to support

  12. Usman says:

    Thx alot for this code..

  13. This is a greta script, Martin, and I’d like to use it on my web site to replace the clunky “Back to top” links I currently have. The only issue is that to fit in with the style of the site, I need the “TOP” box to have rounded corners and all my attempts to do this (even trying to use the jQuery $(‘.element’).corner(); script I use on the rest of the page) have been in vain. Can you offer any suggestions?

    • In the code above I’ve used border-radius:3px;, but you can of course change it’s value to whatever you feel looks best.
      For best possible browser support, you should prefix with -webkit- and -moz- as well.

      Here’s an example with a 10px border radius:

      #footer #scroll-top {
        -webkit-border-radius: 10px; 
        -moz-border-radius: 10px; 

      Good luck!

  14. Hi Martin, Yes -you’re absolutely right – that works a charm. I was trying the code out at work where they use IE that’s a couple of releases out of date – the TOP box was perfectly square, but once I got home and tried it on FF I could see the rounding. Thanks for your very prompt and useful response.

  15. shagun says:

    Nice and easy tutorial.

  16. Sajjad says:

    Hi martin, great and helpful tutorial. I am using this , I think this is also simple
    $(document).ready(function(e) {
    var a = 400,
    t = 1200,
    l = 700,
    s = e(“.scrool-top”);
    e(window).scroll(function() {
    e(this).scrollTop() > a ? s.addClass(“scrool-is-visible”) : s.removeClass(“scrool-is-visible scrool-fade-out”), e(this).scrollTop() > t && s.addClass(“scrool-fade-out”)
    }), s.on(“click”, function(a) {
    a.preventDefault(), e(“body,html”).animate({
    scrollTop: 0
    }, l)

  17. Anto Ramana says:

    beautiful ‘go to top’ animation.,
    can i put in blogger.? how?