Tracking Scroll Positions
In this page:
$(window).scrollTop();
$(selector).scrollTop(value);
$(selector).scrollLeft(value);
Reading Window Scroll
Calling $(window).scrollTop() with no argument returns the number of pixels the whole page has been scrolled down from the top. This is the basis for features like showing a 'back to top' button once the user scrolls past a certain point.
Example: Reading Window Scroll
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
body { font-family: sans-serif; padding: 12px; }
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
button.secondary, #resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
input[type=text] { padding: 6px 8px; margin: 0 6px 8px 0; border: 1px solid #888; border-radius: 4px; font: 14px sans-serif; }
.stage { border: 2px dashed #888; border-radius: 4px; padding: 10px; margin: 8px 0; min-height: 40px; background: #fafafa; }
.stage::before { content: attr(data-label); display: block; font-size: 12px; color: #666; margin-bottom: 6px; }
.item { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
.fresh { background: #ffe066 !important; border-color: #d4a600 !important; }
.done { text-decoration: line-through; color: #a33; }
ul.stage { padding-left: 32px; }
ul.stage:empty::after { content: "(empty)"; color: #999; }
ul.stage > li { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
.box { border: 2px solid #4a7fb5; background: #f3f8fd; border-radius: 4px; padding: 8px 10px; margin: 8px 0; min-height: 54px; }
.box .label { display: block; font-weight: bold; margin-bottom: 6px; color: #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; white-space:pre-wrap; }
#output:empty::before { content: "Output appears here"; color: #888; }
#panel { position: relative; height: 150px; overflow: auto; border: 2px solid navy; background: #fff; margin: 8px 0; }
#tall { position: relative; height: 600px; background: repeating-linear-gradient(180deg, #eaf2fb 0 100px, #d6e6f7 100px 200px); }
#tall .tick { position: absolute; left: 0; width: 100%; border-top: 1px solid #4a7fb5; font-size: 12px; color: #2c6aa0; padding-left: 6px; }
#target { position: absolute; top: 340px; left: 10px; right: 10px; padding: 8px 10px; background: gold; border: 2px solid #b8860b; font-weight: bold; }
.hint { font-size: 13px; color: #555; margin: 4px 0; }
</style>
</head>
<body>
<button id="runBtn">Read scrollTop()</button><button id="resetBtn" class="secondary">Reset</button>
<p class="hint">Scroll inside the box first, then press the button.</p>
<div id="panel"><div id="tall"><div class="tick" style="top:0px">0 px</div><div class="tick" style="top:100px">100 px</div><div class="tick" style="top:200px">200 px</div><div class="tick" style="top:300px">300 px</div><div class="tick" style="top:400px">400 px</div><div class="tick" style="top:500px">500 px</div></div></div>
<div id="output"></div>
<script>
function pos() { return "#panel scrollTop() = " + $("#panel").scrollTop() + " (max " + ($("#panel")[0].scrollHeight - $("#panel").innerHeight()) + ")"; }
$("#runBtn").click(function () {
$("#output").text(pos() + "\n$(window).scrollTop() = " + $(window).scrollTop() + " (the whole page)");
});
$("#resetBtn").click(function () {
$("#panel").scrollTop(0);
$("#output").text("");
});
</script>
</body>
</html>
Reading Element Scroll
scrollTop() also works on individual scrollable elements, not just the window, returning how far that specific element's content has scrolled. This is useful for a scrollable panel or chat box that has its own independent scroll position.
Example: Reading Element Scroll
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
body { font-family: sans-serif; padding: 12px; }
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
button.secondary, #resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
input[type=text] { padding: 6px 8px; margin: 0 6px 8px 0; border: 1px solid #888; border-radius: 4px; font: 14px sans-serif; }
.stage { border: 2px dashed #888; border-radius: 4px; padding: 10px; margin: 8px 0; min-height: 40px; background: #fafafa; }
.stage::before { content: attr(data-label); display: block; font-size: 12px; color: #666; margin-bottom: 6px; }
.item { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
.fresh { background: #ffe066 !important; border-color: #d4a600 !important; }
.done { text-decoration: line-through; color: #a33; }
ul.stage { padding-left: 32px; }
ul.stage:empty::after { content: "(empty)"; color: #999; }
ul.stage > li { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
.box { border: 2px solid #4a7fb5; background: #f3f8fd; border-radius: 4px; padding: 8px 10px; margin: 8px 0; min-height: 54px; }
.box .label { display: block; font-weight: bold; margin-bottom: 6px; color: #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; white-space:pre-wrap; }
#output:empty::before { content: "Output appears here"; color: #888; }
#panel { position: relative; height: 150px; overflow: auto; border: 2px solid navy; background: #fff; margin: 8px 0; }
#tall { position: relative; height: 600px; background: repeating-linear-gradient(180deg, #eaf2fb 0 100px, #d6e6f7 100px 200px); }
#tall .tick { position: absolute; left: 0; width: 100%; border-top: 1px solid #4a7fb5; font-size: 12px; color: #2c6aa0; padding-left: 6px; }
#target { position: absolute; top: 340px; left: 10px; right: 10px; padding: 8px 10px; background: gold; border: 2px solid #b8860b; font-weight: bold; }
.hint { font-size: 13px; color: #555; margin: 4px 0; }
</style>
</head>
<body>
<button id="runBtn">Read #panel scrollTop()</button><button id="resetBtn" class="secondary">Reset</button>
<p class="hint">Scroll the panel with your mouse or scrollbar, then press the button.</p>
<div id="panel"><div id="tall"><div class="tick" style="top:0px">0 px</div><div class="tick" style="top:100px">100 px</div><div class="tick" style="top:200px">200 px</div><div class="tick" style="top:300px">300 px</div><div class="tick" style="top:400px">400 px</div><div class="tick" style="top:500px">500 px</div></div></div>
<div id="output"></div>
<script>
function pos() { return "#panel scrollTop() = " + $("#panel").scrollTop() + " (max " + ($("#panel")[0].scrollHeight - $("#panel").innerHeight()) + ")"; }
$("#runBtn").click(function () { $("#output").text(pos()); });
$("#resetBtn").click(function () {
$("#panel").scrollTop(0);
$("#output").text("");
});
</script>
</body>
</html>
Setting Scroll Position
scrollTop() can set the vertical scroll position by passing a pixel value, immediately moving the page or element to that position. Combined with jQuery's animate(), this is also how you build a smooth scrolling effect.
Example: Setting Scroll Position
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
body { font-family: sans-serif; padding: 12px; }
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
button.secondary, #resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
input[type=text] { padding: 6px 8px; margin: 0 6px 8px 0; border: 1px solid #888; border-radius: 4px; font: 14px sans-serif; }
.stage { border: 2px dashed #888; border-radius: 4px; padding: 10px; margin: 8px 0; min-height: 40px; background: #fafafa; }
.stage::before { content: attr(data-label); display: block; font-size: 12px; color: #666; margin-bottom: 6px; }
.item { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
.fresh { background: #ffe066 !important; border-color: #d4a600 !important; }
.done { text-decoration: line-through; color: #a33; }
ul.stage { padding-left: 32px; }
ul.stage:empty::after { content: "(empty)"; color: #999; }
ul.stage > li { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
.box { border: 2px solid #4a7fb5; background: #f3f8fd; border-radius: 4px; padding: 8px 10px; margin: 8px 0; min-height: 54px; }
.box .label { display: block; font-weight: bold; margin-bottom: 6px; color: #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; white-space:pre-wrap; }
#output:empty::before { content: "Output appears here"; color: #888; }
#panel { position: relative; height: 150px; overflow: auto; border: 2px solid navy; background: #fff; margin: 8px 0; }
#tall { position: relative; height: 600px; background: repeating-linear-gradient(180deg, #eaf2fb 0 100px, #d6e6f7 100px 200px); }
#tall .tick { position: absolute; left: 0; width: 100%; border-top: 1px solid #4a7fb5; font-size: 12px; color: #2c6aa0; padding-left: 6px; }
#target { position: absolute; top: 340px; left: 10px; right: 10px; padding: 8px 10px; background: gold; border: 2px solid #b8860b; font-weight: bold; }
.hint { font-size: 13px; color: #555; margin: 4px 0; }
</style>
</head>
<body>
<button id="runBtn">scrollTop(300)</button><button id="topBtn">scrollTop(0)</button><button id="bottomBtn">Scroll to bottom</button><button id="resetBtn" class="secondary">Reset</button>
<div id="panel"><div id="tall"><div class="tick" style="top:0px">0 px</div><div class="tick" style="top:100px">100 px</div><div class="tick" style="top:200px">200 px</div><div class="tick" style="top:300px">300 px</div><div class="tick" style="top:400px">400 px</div><div class="tick" style="top:500px">500 px</div></div></div>
<div id="output"></div>
<script>
function pos() { return "#panel scrollTop() = " + $("#panel").scrollTop() + " (max " + ($("#panel")[0].scrollHeight - $("#panel").innerHeight()) + ")"; }
$("#runBtn").click(function () { $("#panel").scrollTop(300); $("#output").text("scrollTop(300) -> " + pos()); });
$("#topBtn").click(function () { $("#panel").scrollTop(0); $("#output").text("scrollTop(0) -> " + pos()); });
$("#bottomBtn").click(function () {
$("#panel").scrollTop($("#panel")[0].scrollHeight);
$("#output").text("scrollTop(scrollHeight) -> " + pos());
});
$("#resetBtn").click(function () { $("#panel").scrollTop(0); $("#output").text(""); });
</script>
</body>
</html>
Example: Scroll to Top and Bottom Buttons
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
body { font-family: sans-serif; padding: 12px; }
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
button.secondary, #resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
input[type=text] { padding: 6px 8px; margin: 0 6px 8px 0; border: 1px solid #888; border-radius: 4px; font: 14px sans-serif; }
.stage { border: 2px dashed #888; border-radius: 4px; padding: 10px; margin: 8px 0; min-height: 40px; background: #fafafa; }
.stage::before { content: attr(data-label); display: block; font-size: 12px; color: #666; margin-bottom: 6px; }
.item { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
.fresh { background: #ffe066 !important; border-color: #d4a600 !important; }
.done { text-decoration: line-through; color: #a33; }
ul.stage { padding-left: 32px; }
ul.stage:empty::after { content: "(empty)"; color: #999; }
ul.stage > li { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
.box { border: 2px solid #4a7fb5; background: #f3f8fd; border-radius: 4px; padding: 8px 10px; margin: 8px 0; min-height: 54px; }
.box .label { display: block; font-weight: bold; margin-bottom: 6px; color: #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; white-space:pre-wrap; }
#output:empty::before { content: "Output appears here"; color: #888; }
#panel { position: relative; height: 150px; overflow: auto; border: 2px solid navy; background: #fff; margin: 8px 0; }
#tall { position: relative; height: 600px; background: repeating-linear-gradient(180deg, #eaf2fb 0 100px, #d6e6f7 100px 200px); }
#tall .tick { position: absolute; left: 0; width: 100%; border-top: 1px solid #4a7fb5; font-size: 12px; color: #2c6aa0; padding-left: 6px; }
#target { position: absolute; top: 340px; left: 10px; right: 10px; padding: 8px 10px; background: gold; border: 2px solid #b8860b; font-weight: bold; }
.hint { font-size: 13px; color: #555; margin: 4px 0; }
</style>
</head>
<body>
<button id="runBtn">Scroll to Top</button><button id="bottomBtn">Scroll to Bottom</button><button id="resetBtn" class="secondary">Reset</button>
<p class="hint">Scroll down inside the panel, then use the buttons.</p>
<div id="panel"><div id="tall"><div class="tick" style="top:0px">0 px</div><div class="tick" style="top:100px">100 px</div><div class="tick" style="top:200px">200 px</div><div class="tick" style="top:300px">300 px</div><div class="tick" style="top:400px">400 px</div><div class="tick" style="top:500px">500 px</div></div></div>
<div id="output"></div>
<script>
function pos() { return "#panel scrollTop() = " + $("#panel").scrollTop() + " (max " + ($("#panel")[0].scrollHeight - $("#panel").innerHeight()) + ")"; }
$("#panel").on("scroll", function () { $("#output").text(pos()); });
$("#runBtn").click(function () {
$("#panel").stop(true).animate({scrollTop: 0}, 400);
});
$("#bottomBtn").click(function () {
$("#panel").stop(true).animate({scrollTop: $("#panel")[0].scrollHeight}, 400);
});
$("#resetBtn").click(function () { $("#panel").stop(true).scrollTop(0); });
$("#output").text(pos());
</script>
</body>
</html>
Scroll Events
The scroll event fires whenever a scrollable area -- the window or an individual element -- changes position, letting you react as the user scrolls. Because it can fire very frequently, scroll handlers are often throttled to avoid doing expensive work on every pixel of movement.
Example: Scroll Events
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
body { font-family: sans-serif; padding: 12px; }
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
button.secondary, #resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
input[type=text] { padding: 6px 8px; margin: 0 6px 8px 0; border: 1px solid #888; border-radius: 4px; font: 14px sans-serif; }
.stage { border: 2px dashed #888; border-radius: 4px; padding: 10px; margin: 8px 0; min-height: 40px; background: #fafafa; }
.stage::before { content: attr(data-label); display: block; font-size: 12px; color: #666; margin-bottom: 6px; }
.item { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
.fresh { background: #ffe066 !important; border-color: #d4a600 !important; }
.done { text-decoration: line-through; color: #a33; }
ul.stage { padding-left: 32px; }
ul.stage:empty::after { content: "(empty)"; color: #999; }
ul.stage > li { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
.box { border: 2px solid #4a7fb5; background: #f3f8fd; border-radius: 4px; padding: 8px 10px; margin: 8px 0; min-height: 54px; }
.box .label { display: block; font-weight: bold; margin-bottom: 6px; color: #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; white-space:pre-wrap; }
#output:empty::before { content: "Output appears here"; color: #888; }
#panel { position: relative; height: 150px; overflow: auto; border: 2px solid navy; background: #fff; margin: 8px 0; }
#tall { position: relative; height: 600px; background: repeating-linear-gradient(180deg, #eaf2fb 0 100px, #d6e6f7 100px 200px); }
#tall .tick { position: absolute; left: 0; width: 100%; border-top: 1px solid #4a7fb5; font-size: 12px; color: #2c6aa0; padding-left: 6px; }
#target { position: absolute; top: 340px; left: 10px; right: 10px; padding: 8px 10px; background: gold; border: 2px solid #b8860b; font-weight: bold; }
.hint { font-size: 13px; color: #555; margin: 4px 0; }
</style>
</head>
<body>
<button id="resetBtn">Scroll back to top</button>
<p class="hint">Scroll the panel: the scroll event updates the output below.</p>
<div id="panel"><div id="tall"><div class="tick" style="top:0px">0 px</div><div class="tick" style="top:100px">100 px</div><div class="tick" style="top:200px">200 px</div><div class="tick" style="top:300px">300 px</div><div class="tick" style="top:400px">400 px</div><div class="tick" style="top:500px">500 px</div></div></div>
<div id="output">Scroll the panel above...</div>
<script>
var count = 0;
$("#panel").on("scroll", function () {
count++;
$("#output").text("scroll event #" + count + "\nscrollTop() = " + $(this).scrollTop());
});
$("#resetBtn").click(function () { $("#panel").scrollTop(0); });
</script>
</body>
</html>
Scroll to an Element
You can combine an element's offset() coordinates with scrollTop() to move the page so that a specific element comes into view. This is the basic technique behind 'jump to section' links and smooth-scrolling navigation menus.
Example: Scroll to an Element
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
body { font-family: sans-serif; padding: 12px; }
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
button.secondary, #resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
input[type=text] { padding: 6px 8px; margin: 0 6px 8px 0; border: 1px solid #888; border-radius: 4px; font: 14px sans-serif; }
.stage { border: 2px dashed #888; border-radius: 4px; padding: 10px; margin: 8px 0; min-height: 40px; background: #fafafa; }
.stage::before { content: attr(data-label); display: block; font-size: 12px; color: #666; margin-bottom: 6px; }
.item { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
.fresh { background: #ffe066 !important; border-color: #d4a600 !important; }
.done { text-decoration: line-through; color: #a33; }
ul.stage { padding-left: 32px; }
ul.stage:empty::after { content: "(empty)"; color: #999; }
ul.stage > li { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
.box { border: 2px solid #4a7fb5; background: #f3f8fd; border-radius: 4px; padding: 8px 10px; margin: 8px 0; min-height: 54px; }
.box .label { display: block; font-weight: bold; margin-bottom: 6px; color: #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; white-space:pre-wrap; }
#output:empty::before { content: "Output appears here"; color: #888; }
#panel { position: relative; height: 150px; overflow: auto; border: 2px solid navy; background: #fff; margin: 8px 0; }
#tall { position: relative; height: 600px; background: repeating-linear-gradient(180deg, #eaf2fb 0 100px, #d6e6f7 100px 200px); }
#tall .tick { position: absolute; left: 0; width: 100%; border-top: 1px solid #4a7fb5; font-size: 12px; color: #2c6aa0; padding-left: 6px; }
#target { position: absolute; top: 340px; left: 10px; right: 10px; padding: 8px 10px; background: gold; border: 2px solid #b8860b; font-weight: bold; }
.hint { font-size: 13px; color: #555; margin: 4px 0; }
</style>
</head>
<body>
<button id="runBtn">Jump to target</button><button id="animBtn">Animate to target</button><button id="resetBtn" class="secondary">Reset</button>
<div id="panel"><div id="tall"><div class="tick" style="top:0px">0 px</div><div class="tick" style="top:100px">100 px</div><div class="tick" style="top:200px">200 px</div><div class="tick" style="top:300px">300 px</div><div class="tick" style="top:400px">400 px</div><div class="tick" style="top:500px">500 px</div><div id="target">Target section</div></div></div>
<div id="output"></div>
<script>
function targetTop() { return $("#target").offset().top - $("#tall").offset().top; }
$("#runBtn").click(function () {
var top = targetTop();
$("#panel").scrollTop(top);
$("#output").text("target is " + top + "px from the top of the content\nscrollTop() is now " + $("#panel").scrollTop());
});
$("#animBtn").click(function () {
var top = targetTop();
$("#output").text("animating to " + top + "px...");
$("#panel").stop(true).animate({scrollTop: top}, 500, function () {
$("#output").text("arrived: scrollTop() = " + $("#panel").scrollTop());
});
});
$("#resetBtn").click(function () { $("#panel").stop(true).scrollTop(0); $("#output").text(""); });
</script>
</body>
</html>
- Calling
$("#panel").scrollTop()on an element that is not scrollable, which always returns 0 because it needsoverflow:autoorscroll. - Reading
scrollTop()once and expecting it to update, when it must be read again inside ascrollevent handler. - Using
$("body").scrollTop()for the page in some browsers, when$(window).scrollTop()is the dependable form.
- jQuery gets and sets CSS rules and manages classes on elements.
- It reads element width, height, and inner and outer dimensions.
- It also reports element coordinates and tracks scroll positions.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: