Skip to content

jQuery Scrolling — Complete Guide to .scrollTop(), Scroll Events, and Animations

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about jquery scrolling. We cover key concepts, practical examples, and best practices to help you master this topic.

jQuery scrolling methods let you read and control scroll position, detect scroll events, animate smooth scrolling to elements, and build scroll-based UI behaviors like Infinite Scroll and sticky headers.

What You'll Learn

  • Getting and setting scroll position with .scrollTop() and .scrollLeft()
  • Scrolling to elements with .animate()
  • Detecting scroll events and throttling
  • Building infinite scroll and sticky navigation
  • Smooth scroll implementations

Why It Matters

Scrolling is one of the most common user interactions. Controlling scroll position and responding to scroll events is essential for navigation, Lazy Loading, progress indicators, and scroll-triggered animations.

Real-World Use

A blog with infinite scroll that loads more posts when the user reaches the bottom, a sticky table of contents that highlights the current section on scroll, and a "Back to Top" button that animates smoothly up.

Scroll Flow

flowchart TD
    A[User Scrolls] --> B[scroll Event]
    B --> C[Throttle/Debounce]
    C --> D[Check Position]
    D --> E{Near Bottom?}
    D --> F{Past Header?}
    E -->|Yes| G[Load More Content]
    F -->|Yes| H[Stick Header]
    F -->|No| I[Unstick Header]
    style B fill:#e6f3ff,stroke:#4a90d9,stroke-width:2px

Getting and Setting Scroll Position

// Get scroll position
var scrollTop = $(window).scrollTop();
var scrollLeft = $(window).scrollLeft();
console.log('Scroll position:', scrollTop, scrollLeft);

// Set scroll position
$(window).scrollTop(0);          // Scroll to top
$(window).scrollLeft(200);       // Scroll 200px from left

// Scroll a specific element (not window)
var $container = $('.scrollable-div');
var pos = $container.scrollTop();
$container.scrollTop(100);

Expected output: .scrollTop() returns the number of pixels the element is scrolled vertically. Setting it scrolls to that position immediately.

Smooth Scrolling to an Element

// Smooth scroll to an element
$('html, body').animate({
  scrollTop: $('#section2').offset().top - 20 // 20px offset
}, 500);

// With easing
$('html, body').animate({
  scrollTop: $('#target').offset().top
}, {
  duration: 800,
  easing: 'swing',
  complete: function() {
    console.log('Scroll complete');
  }
});

// Click handler for anchor links
$('a[href^="#"]').on('click', function(e) {
  e.preventDefault();
  var target = $(this.getAttribute('href'));
  if (target.length) {
    $('html, body').animate({
      scrollTop: target.offset().top - 50
    }, 600);
  }
});

Expected output: The page smoothly scrolls to the target element's position, stopping 50px above it for a fixed header.

Scroll Event Detection

$(window).on('scroll', function() {
  var scrollPos = $(window).scrollTop();
  console.log('Scrolled:', scrollPos);
});

Throttling Scroll Events

Scroll events fire rapidly. Always throttle or debounce:

// Throttle: fire at most once per 200ms
var lastScrollTime = 0;
$(window).on('scroll', function() {
  var now = Date.now();
  if (now - lastScrollTime < 200) return;
  lastScrollTime = now;

  // Your scroll logic here
  var scrollPos = $(window).scrollTop();
  updateUI(scrollPos);
});

// Or use a debounce timer
var scrollTimer;
$(window).on('scroll', function() {
  clearTimeout(scrollTimer);
  scrollTimer = setTimeout(function() {
    // Fires 100ms after scrolling stops
    var pos = $(window).scrollTop();
    console.log('Scroll stopped at:', pos);
  }, 100);
});

Sticky Header on Scroll

var header = $('.site-header');
var stickyClass = 'sticky';
var headerOffset = header.offset().top;

$(window).on('scroll', function() {
  var scrollPos = $(window).scrollTop();

  if (scrollPos >= headerOffset) {
    header.addClass(stickyClass);
  } else {
    header.removeClass(stickyClass);
  }
});

// CSS:
// .site-header.sticky {
//   position: fixed;
//   top: 0;
//   left: 0;
//   right: 0;
//   z-index: 1000;
//   box-shadow: 0 2px 4px rgba(0,0,0,0.1);
// }

Back to Top Button

var $backToTop = $('<button class="back-to-top">Top</button>')
  .appendTo('body')
  .hide();

$(window).on('scroll', function() {
  if ($(window).scrollTop() > 300) {
    $backToTop.fadeIn();
  } else {
    $backToTop.fadeOut();
  }
});

$backToTop.on('click', function() {
  $('html, body').animate({ scrollTop: 0 }, 400);
});

Expected output: The button fades in after scrolling 300px down. Clicking it animates smoothly back to the top.

Infinite Scroll

var page = 1;
var loading = false;

$(window).on('scroll', function() {
  if (loading) return;

  var scrollTop = $(window).scrollTop();
  var windowHeight = $(window).height();
  var docHeight = $(document).height();

  // Trigger when within 200px of the bottom
  if (scrollTop + windowHeight >= docHeight - 200) {
    loading = true;
    $('#loading-spinner').show();

    page++;

    $.get('/api/items?page=' + page, function(data) {
      if (data.items.length > 0) {
        data.items.forEach(function(item) {
          $('.items-list').append(
            $('<div class="item">').text(item.name)
          );
        });
        loading = false;
        $('#loading-spinner').hide();
      } else {
        // No more items
        $('#loading-spinner').text('No more items');
      }
    });
  }
});

Scroll Progress Indicator

$(window).on('scroll', function() {
  var scrollTop = $(window).scrollTop();
  var docHeight = $(document).height() - $(window).height();
  var scrollPercent = (scrollTop / docHeight) * 100;

  $('.progress-bar').width(scrollPercent + '%');
});

// CSS:
// .progress-bar {
//   position: fixed;
//   top: 0;
//   left: 0;
//   height: 3px;
//   background: #3498db;
//   transition: width 0.1s;
// }

Scrollable Container

// Create a custom scrollable div
var $container = $('<div class="scroll-container">')
  .css({
    width: '400px',
    height: '300px',
    overflow: 'auto'
  })
  .appendTo('body');

$container.on('scroll', function() {
  var $this = $(this);
  var scrollTop = $this.scrollTop();
  var scrollHeight = this.scrollHeight;
  var clientHeight = this.clientHeight;

  if (scrollTop + clientHeight >= scrollHeight - 50) {
    console.log('Reached bottom of container');
  }
});

Common Mistakes

  1. Not throttling scroll events - Scroll fires hundreds of times per second. Without throttling, your handlers cause jank and poor performance.

  2. Using $(window).scrollTop() on non-window elements - For scrollable divs, use $('.container').scrollTop(), not $(window).scrollTop().

  3. Forgetting animation queue on scroll - Calling .animate() inside a scroll handler without .stop() causes queued animations to accumulate. Stop the previous animation first.

  4. Not accounting for fixed headers in scroll-to - When scrolling to an element, subtract the fixed header height: target.offset().top - headerHeight.

  5. Infinite scroll without loading guard - Without a loading flag, scroll triggers at the bottom fire multiple API calls. Always guard against concurrent loads.

Practice Questions

  1. How do you get the current vertical scroll position?
  2. How do you smoothly scroll to a specific element on the page?
  3. Why is throttling important for scroll events?
  4. How do you detect when the user has scrolled to the bottom of the page?
  5. How do you scroll a specific div (not the window)?

Challenge: Build a one-page marketing site with smooth scroll navigation, a sticky header, a scroll progress bar, a "Back to Top" button, and active section highlighting in the navigation as the user scrolls.

FAQ

What is the difference between $(window).scrollTop() and $(document).scrollTop()?

They are functionally equivalent in most browsers. $(window).scrollTop() is the more commonly used and reliable approach.

Can I detect scroll direction?

Yes. Store the previous scroll position and compare: if (current > previous) // scrolling down; else // scrolling up.

Does .animate({ scrollTop }) work on all elements?

Yes, as long as the element has overflow that enables scrolling (overflow: auto or scroll). It works on window, document, and any scrollable div.

How do I prevent scroll when a modal is open?

Set $('body').css('overflow', 'hidden') to disable scroll on open and restore 'auto' on close.

What is the performance impact of scroll listeners?

Unthrottled scroll listeners cause layout thrashing and jank. Always throttle to at most 50-100ms intervals for smooth performance.

Mini Project

Build a scroll-driven story page with sections that fade in and animate when they scroll into view (scroll-triggered animations). Include a scroll-based progress bar, smooth navigation between sections, and a floating table of contents that highlights the active section.

What's Next

Scroll interactions respond to jQuery events. Learn more about binding and managing events in jQuery.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro