The scroll event fires when scroll position changes inside an element. This tutorial covers .on("scroll") on overflow containers and $(window), logging to #log, .trigger("scroll"), page-scroll indicators, reading scrollTop, throttling fast handlers, the official jQuery API demos, and how this differs from resize, .scrollTop(), and the deprecated .scroll() method.
01
.on()
Bind handler
02
#target
Overflow box
03
$(window)
Page scroll
04
Throttle
Limit work
05
.trigger()
Fire scroll
06
Since 1.7
Modern API
Fundamentals
Introduction
Sticky headers, infinite scroll feeds, and reading progress bars all react when the user moves through content. The scroll event is jQuery’s hook for that moment — when scroll position changes inside a scrollable element, whether that element is the browser window or a div with overflowing content.
The official jQuery API distinguishes the scrollevent (bound with .on("scroll") since 1.7) from the deprecated .scroll()method (legacy shorthand, deprecated since 3.3). To programmatically run scroll handlers, use .trigger("scroll") since jQuery 1.0.
Concept
Understanding the scroll Event
The scroll event is sent to an element when the user scrolls to a different place in the element. jQuery wraps the native event so you can bind with $("#target").on("scroll", handler) or $(window).on("scroll", handler) and chain further calls on the same collection.
It applies to window objects, scrollable frames, and elements with the overflow CSS property set to scroll or auto when the element’s explicit height or width is less than its contents. Scroll fires whenever scroll position changes — mouse wheel, scrollbar drag, arrow keys, touch, or programmatic .scrollTop() changes.
💡
Beginner Tip
Bind on the element that actually scrolls. Use $(window) for page scroll and $("#panel") for an overflow container — binding on a parent that does not scroll will never fire.
Foundation
📝 Syntax
The modern jQuery API for the scroll event has two main forms — binding a handler and triggering the event:
jQuery also provided .scroll(handler) as a legacy binding shorthand and no-arg .scroll() to trigger the event. The binding form is deprecated since jQuery 3.3 — see the jQuery .scroll() method tutorial (coming soon) or migrate to .on("scroll") and .trigger("scroll").
Return value
.on() and .trigger() return the original jQuery object for chaining.
Inside the handler, this refers to the DOM element that scrolled — use $(this).scrollTop() or $(window).scrollTop() for the current offset.
Cheat Sheet
⚡ Quick Reference
Goal
Code
Bind scroll on overflow element
$("#target").on("scroll", fn)
Bind scroll on page (window)
$(window).on("scroll", fn)
Append scroll log lines
$("#log").append("Handler called. ")
Read vertical scroll offset
$(window).scrollTop() inside handler
Trigger scroll programmatically
$("#target").trigger("scroll")
Throttle expensive scroll work
if (Date.now() - last >= 150) { ... }
Remove scroll handlers
$(window).off("scroll")
Compare
📋 scroll vs resize vs .scrollTop() vs deprecated .scroll()
Four related concepts that sound similar — know which reacts to scroll position, viewport size, programmatic offset, and legacy jQuery shorthand.
scroll event
element
Scroll position changed inside a scrollable element — bind with .on("scroll") on window or overflow containers; fires on wheel, scrollbar, keys, and drag
resize event
window
Browser viewport size changed — bind with .on("resize") on $(window); not the same as content scrolling inside the page
.scrollTop() method
get/set
Get or set vertical scroll offset in pixels — use to jump to top or read position; pair with scroll event handlers for reactive UI
.scroll() method
deprecated
Legacy bind (.scroll(fn)) or trigger (.scroll()) — deprecated since 3.3; use .on("scroll") and .trigger("scroll") in new code
Hands-On
Examples Gallery
Examples 1–3 follow the official jQuery API documentation. Examples 4–5 extend the pattern with a scrollTop progress bar and throttled container scroll. Use the Try-it links to run each snippet in the browser.
📚 Official API Demos
Official jQuery demos for logging scroll on #target, triggering scroll, and reacting to page scroll.
Example 1 — Official Demo: Append to #log on #target Scroll
Log each scroll call when the user scrolls inside a scrollable div — from the jQuery API documentation.
Page loads → handler bound on #target
Scroll inside the blue box → #log gains:
Handler for scroll called.
Fires on wheel, scrollbar drag, arrow keys, or touch inside #target
How It Works
Binding on #target catches every scroll position change inside that overflow container. Appending to #log makes the firing pattern visible — scroll the Try-it panel to see how often the event fires.
Example 2 — Official Demo: #other Triggers Scroll on #target
Fire scroll handlers programmatically with a button click — official jQuery API pattern.
Click Trigger the handler → trigger("scroll") runs bound handler
#log shows: Handler for scroll called.
Works even when scroll position did not change — handlers still run
How It Works
.trigger("scroll") synthetically fires the event on #target. Bound handlers run even though the user did not scroll — ideal for testing or syncing UI after programmatic .scrollTop() changes.
Example 3 — Official Demo: $(window).on("scroll") Page Indicator
Show a message when the page is scrolled — official jQuery API window scroll pattern.
Scroll the page → red badge appears briefly
Badge fades out over 800 ms (official span fadeOut pattern)
Bind on $(window) for document-level scroll, not inner containers
How It Works
$(window).on("scroll") listens for page scroll. The official API uses a span that fades out; this tutorial’s Try-it uses #msg with the same show-and-fade pattern via .stop(true, true).fadeOut().
📈 Production Patterns
Read scrollTop for progress UI and throttle handlers on fast-scrolling containers.
Example 4 — scrollTop Reading Progress Bar
Read $(window).scrollTop() inside the scroll handler to drive a fixed progress bar.
jQuery
function updateProgress() {
var st = $( window ).scrollTop();
var max = $( document ).height() - $( window ).height();
var pct = max > 0 ? Math.round( ( st / max ) * 100 ) : 0;
$( "#bar" ).css( "width", pct + "%" );
$( "#pct" ).text( pct + "%" );
}
$( window ).on( "scroll", updateProgress );
updateProgress();
Scroll page → top bar width grows from 0% to 100%
#pct shows current percentage
scrollTop / (document height − window height) = progress ratio
How It Works
The scroll event tells you when position changed; .scrollTop() tells you where. Dividing current offset by the maximum scrollable distance yields a percentage for progress bars, lazy-load thresholds, and section spy navigation.
Example 5 — Throttled Scroll Handler on #panel
Limit how often expensive scroll work runs — handlers can fire very frequently during fast scrolling.
jQuery
var raw = 0, th = 0, last = 0;
$( "#panel" ).on( "scroll", function() {
raw++;
$( "#raw" ).text( raw );
var now = Date.now();
if ( now - last >= 150 ) {
last = now;
th++;
$( "#th" ).text( th );
}
} );
Fast scroll inside #panel → raw count climbs quickly
Throttled runs increment only every 150 ms
Heavy work should use the throttled path, not every raw event
How It Works
A timestamp gate collapses dozens of scroll events into periodic updates. This is the standard pattern for parallax, sticky sidebars, and any DOM measurement that would stutter if run on every intermediate pixel during a fast flick scroll.
Applications
🚀 Common Use Cases
Sticky headers and nav — toggle fixed positioning or shadow classes when $(window).scrollTop() passes a threshold.
Reading progress bars — update a top bar or sidebar indicator as the user moves through long articles.
Infinite scroll feeds — load the next page when scroll nears the bottom of a container or the document.
Scroll-spy navigation — highlight the active section link based on which heading is currently in view.
Overflow panel sync — bind on chat logs, data tables, or map sidebars that scroll independently of the page.
Manual scroll notifications — use .trigger("scroll") after programmatic .scrollTop() changes so widgets that only listen for scroll also update.
🚀 How the scroll Event Flows
1
Handler bound on scrollable element
Code calls $("#target").on("scroll", fn) or $(window).on("scroll", fn) — optionally with eventData for config objects.
bind
2
Scroll position changes
The user wheels, drags the scrollbar, presses arrow keys, or touches a trackpad. The browser sends scroll to the element whose offset changed — window or overflow container.
native
3
Handler runs (maybe many times)
jQuery invokes your callback. Read scrollTop, update progress UI, or queue throttled work — scroll can fire dozens of times per second during fast movement.
handler
4
📄
UI reflects scroll position
Indicators, lazy loads, and sticky nav stay in sync. For programmatic changes, call .trigger("scroll") so widgets that only listen for scroll also update.
Important
📝 Notes
Bind with .on("scroll", handler) since jQuery 1.7 — not the deprecated .scroll() shorthand.
Trigger with .trigger("scroll") since jQuery 1.0.
Applies to window, scrollable frames, and elements with overflow:scroll or overflow:auto when content overflows.
Scroll fires whenever scroll position changes — wheel, scrollbar, keys, drag, or touch — regardless of the cause.
Throttle or debounce expensive layout, measurement, and animation code inside scroll handlers.
scroll is not resize — resize fires when viewport size changes, not when content position moves.
The scroll event is not .scrollTop() — that method gets or sets offset; the event notifies you when offset changes.
Use .off("scroll") to remove handlers — avoid deprecated .unbind("scroll") or legacy .scroll().
Compatibility
Browser Support
The scroll event is a standard DOM event on scrollable elements and window, supported in every browser jQuery targets. jQuery’s .on("scroll") (since 1.7) and .trigger("scroll") (since 1.0) provide consistent binding and chaining. Scroll can fire very frequently — throttle production handlers.
✓ jQuery 1.7+
jQuery scroll event
Supported in jQuery 1.x, 2.x, and 3.x across all modern browsers and IE with supported jQuery versions. Native equivalent: element.addEventListener('scroll', fn) — jQuery adds collection binding, eventData, and .trigger() in one chainable API.
100%With jQuery loaded
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
scrollUniversal
Bottom line: Safe in any jQuery project. Prefer .on('scroll') over the deprecated .scroll() method. Bind on the element that scrolls and throttle heavy work.
Wrap Up
Conclusion
The jQuery scroll event is the standard hook for scroll position changes. Bind handlers with .on("scroll", fn) on overflow elements or $(window), read position with .scrollTop(), throttle expensive work, and fire handlers programmatically with .trigger("scroll").
Remember: scroll fires on the element that moves, not on parents that stay fixed; this is not the resize event; and the legacy .scroll() shorthand is deprecated since jQuery 3.3. Pair scroll handlers with .scrollTop() when you need the actual offset.
Bind with .on("scroll", handler) on the element that actually scrolls
Use $(window) for page scroll and $("#panel") for overflow containers
Throttle or debounce layout, parallax, and DOM measurements in scroll handlers
Read .scrollTop() inside handlers when you need the current offset
Call .trigger("scroll") after programmatic scroll position changes
Remove handlers with .off("scroll") when widgets unmount
❌ Don’t
Confuse with deprecated .scroll() — migrate to .on("scroll")
Bind on a parent that does not scroll expecting child scroll events to bubble
Run heavy synchronous work on every scroll fire without throttling
Confuse scroll with resize or with .scrollTop() get/set
Assume scroll fires once per user gesture — count varies with scroll speed
Summary
Key Takeaways
Knowledge Unlocked
Six things to remember about the scroll event
Element, window, throttle.
6
Core concepts
.on01
.on("scroll")
Bind
API
#02
#target
Overflow
Element
win03
$(window)
Page
Target
⏱04
Throttle
No jank
Perf
⚡05
.trigger()
Manual
Programmatic
≠06
Not resize
Position
Compare
❓ Frequently Asked Questions
The scroll event is sent to an element when the user scrolls to a different place in that element. Bind with .on('scroll', handler) since jQuery 1.7. It applies to window, scrollable frames, and elements with overflow:scroll or overflow:auto when content overflows. Scroll fires whenever scroll position changes — wheel, scrollbar drag, arrow keys, or touch — regardless of the cause.
Use $(window).on('scroll', fn) for page-level scroll — back-to-top buttons, sticky headers, and reading progress bars. Bind on a specific element like $('#panel').on('scroll', fn) when only that container scrolls, such as a chat log or data table body. The event target must be the element whose scrollTop or scrollLeft actually changes.
Call $('#target').trigger('scroll') since jQuery 1.0. Bound scroll handlers on that element run as if the user scrolled — useful for testing or syncing UI when you change scroll position with .scrollTop(). Example 2 on this page uses a button to fire trigger('scroll') on #target.
Throttle for visual updates that should stay responsive while scrolling — progress bars, parallax, and sticky nav checks often run every 100–150 ms during scroll. Debounce when you only need the final position after scrolling stops — lazy-loading images near the viewport bottom. Scroll can fire dozens of times per second; never run heavy DOM work on every raw event.
Scroll fires when content position changes inside a scrollable element — the viewport size stays the same. Resize fires on window when the browser viewport width or height changes. A user can scroll without resizing and resize without scrolling. Bind scroll for reading position; bind resize for layout reflow.
They target the same browser scroll event — .scroll(handler) is the legacy shorthand deprecated since jQuery 3.3, while .on('scroll', handler) is the modern replacement since 1.7. Unlike .error(), which was removed in jQuery 3.0, .scroll() still works in jQuery 3.x but should not be used in new code. Do not confuse the scroll event with the .scrollTop() method, which gets or sets scroll position rather than listening for changes.
Did you know?
The jQuery API page for scroll notes that a scroll event is sent whenever the element’s scroll position changes, regardless of the cause — a mouse click or drag on the scroll bar, dragging inside the element, pressing arrow keys, or using the mouse wheel could all trigger it. That is why counting scroll calls is unreliable during fast movement — production code throttles layout work instead. The same page documents that the event applies to window and to elements with overflow:scroll or overflow:auto, which is why you bind on the specific scrollable element rather than expecting all scroll activity to bubble from children.