312

I'm trying to detect the position of the browser's scrollbar with JavaScript to decide where in the page the current view is.

My guess is that I have to detect where the thumb on the track is, and then the height of the thumb as a percentage of the total height of the track. Am I over-complicating it, or does JavaScript offer an easier solution than that? What would some code look like?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Paul
  • 3,123
  • 2
  • 16
  • 5

11 Answers11

308

You can use element.scrollTop and element.scrollLeft to get the vertical and horizontal offset, respectively, that has been scrolled. element can be document.body if you care about the whole page. You can compare it to element.offsetHeight and element.offsetWidth (again, element may be the body) if you need percentages.

Laniakea
  • 3
  • 3
Max Shawabkeh
  • 37,799
  • 10
  • 82
  • 91
  • 2
    What browser are you using? Getting the body is done differently in different browsers (`element` and `document.body` were just examples). See http://www.howtocreate.co.uk/tutorials/javascript/browserwindow for details. – Max Shawabkeh Mar 20 '10 at 01:47
  • 12
    I got it to give me the correct value on Firefox 3.6 with `window.pageYOffset`, but can't get anything working on IE7. Tried `window.pageYOffset`, `document.body.scrollTop`, `document.documentElement.scrollTop`, `element.scrollTop` – Paul Mar 20 '10 at 02:04
  • document.body.scrollLeft is what I needed :) – Jorge Orpinel Pérez Feb 09 '14 at 21:19
  • 1
    scrollTop only worked for me when I added brackets... $(".scrollBody").scrollTop() – maia Jan 05 '17 at 00:47
  • 12
    If you are dealing with the 'window' Element, you may use window.scrollY instead of window.scrollTop – Janis Jansen Aug 04 '17 at 06:16
  • 1
    The scrollTop property isn't W3C standard – Green Feb 05 '18 at 16:16
  • 26
    I think scroll position isn't set on `document.body` in most modern browsers - it's usually set on `document.documentElement` now. See https://bugs.chromium.org/p/chromium/issues/detail?id=157855 for Chrome's transition. – fzzfzzfzz May 03 '18 at 15:51
  • I don't recommend 'scrollTop'. It has known issues and often doesnt work. I am surprised to see how many people rely on this fickle command – Ian Steffy Apr 20 '20 at 07:37
  • There is also `node.scrollWidth` – Marian07 Jun 29 '22 at 16:12
187

I did this for a <div> on Chrome.

element.scrollTop - is the pixels hidden in top due to the scroll. With no scroll its value is 0.

element.scrollHeight - is the pixels of the whole div.

element.clientHeight - is the pixels that you see in your browser.

var a = element.scrollTop;

will be the position.

var b = element.scrollHeight - element.clientHeight;

will be the maximum value for scrollTop.

var c = a / b;

will be the percent of scroll [from 0 to 1].

Community
  • 1
  • 1
Gatsby
  • 1,879
  • 1
  • 11
  • 3
66
document.getScroll = function() {
    if (window.pageYOffset != undefined) {
        return [pageXOffset, pageYOffset];
    } else {
        var sx, sy, d = document,
            r = d.documentElement,
            b = d.body;
        sx = r.scrollLeft || b.scrollLeft || 0;
        sy = r.scrollTop || b.scrollTop || 0;
        return [sx, sy];
    }
}

returns an array with two integers- [scrollLeft, scrollTop]

dYale
  • 1,541
  • 1
  • 16
  • 19
kennebec
  • 102,654
  • 32
  • 106
  • 127
66

It's like this :)

window.addEventListener("scroll", (event) => {
    let scroll = this.scrollY;
    console.log(scroll)
});
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brayan Pastor
  • 874
  • 7
  • 12
  • 14
    Just to be clear `this` in this context is referred to `window`. `scrollY` is a property of `window` – Stefan Feb 08 '21 at 20:58
23

Answer for 2018:

The best way to do things like that is to use the Intersection Observer API.

The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport.

Historically, detecting visibility of an element, or the relative visibility of two elements in relation to each other, has been a difficult task for which solutions have been unreliable and prone to causing the browser and the sites the user is accessing to become sluggish. Unfortunately, as the web has matured, the need for this kind of information has grown. Intersection information is needed for many reasons, such as:

  • Lazy-loading of images or other content as a page is scrolled.
  • Implementing "infinite scrolling" web sites, where more and more content is loaded and rendered as you scroll, so that the user doesn't have to flip through pages.
  • Reporting of visibility of advertisements in order to calculate ad revenues.
  • Deciding whether or not to perform tasks or animation processes based on whether or not the user will see the result.

Implementing intersection detection in the past involved event handlers and loops calling methods like Element.getBoundingClientRect() to build up the needed information for every element affected. Since all this code runs on the main thread, even one of these can cause performance problems. When a site is loaded with these tests, things can get downright ugly.

See the following code example:

var options = {
  root: document.querySelector('#scrollArea'),
  rootMargin: '0px',
  threshold: 1.0
}

var observer = new IntersectionObserver(callback, options);

var target = document.querySelector('#listItem');
observer.observe(target);

Most modern browsers support the IntersectionObserver, but you should use the polyfill for backward-compatibility.

str
  • 42,689
  • 17
  • 109
  • 127
  • 1
    It's an unfortunate weakness in SO that answers that are accepted as correct can become (through no fault of the answerer) wrong, but are stuck as accepted forever. The accepted answer has become entirely wrong now for the document.body case, since, as @fzzfzzfzz said in a comment to the accepted answer, "scroll position isn't set on document.body in most modern browsers - it's usually set on document.documentElement now. See bugs.chromium.org/p/chromium/issues/detail?id=157855 for Chrome's transition." Ideally this 2018 Intersection Observer API answer would be set as the new accepted answer. – Jacob C. Nov 10 '21 at 22:30
22

If you care for the whole page, you can use this:

document.body.getBoundingClientRect().top
lemospy
  • 371
  • 5
  • 8
12

Snippets

The read-only scrollY property of the Window interface returns the number of pixels that the document is currently scrolled vertically.

window.addEventListener('scroll', function(){console.log(this.scrollY)})
html{height:5000px}

Shorter version using anonymous arrow function (ES6) and avoiding the use of this

window.addEventListener('scroll', () => console.log(scrollY))
html{height:5000px}
Gass
  • 7,536
  • 3
  • 37
  • 41
4

Here is the other way to get the scroll position:

const getScrollPosition = (el = window) => ({
  x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
  y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop
});
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Gor
  • 1,385
  • 12
  • 7
3

If you are using jQuery there is a perfect function for you: .scrollTop()

doc here -> http://api.jquery.com/scrollTop/

note: you can use this function to retrieve OR set the position.

see also: http://api.jquery.com/?s=scroll

  • 35
    Why answer a question about JS with a library for JS, when it is completely possible and even convenient to do it in raw JS? You're just asking him to add additional load time as well as use up some storage for something completely unnecessary. Also, since when did javascript start meaning JQuery? –  Apr 02 '16 at 23:57
  • 7
    if you ask individually I never liked jQuery and i haven't answered this question but in Vanilla JS there are already answers given by other fellows then what's a problem if some one have added a tasty spice in this thread.(He already mentioned that if you are using jQuery) – Ravinder Payal Apr 03 '16 at 06:01
  • @R01010010 it's because now days JQuery is useless and counterproductive, all features from JQuery are easy implemented with VanilaJS, also you become depended of what's inside JQuery, with new features avaible in VanillsaJS, you as programer,won't update, just as example, now days there is a new API in VanillaJS called fetch that replaced old XHR, if you just were in the world of JQuery will never see the benefits on fetch and continue using jQuery.ajax().My personal opinion is that people who continue using JQuery it's because they stopped learning. Also VanillaJS is faster vanilla-js.com – John Balvin Arias Jun 06 '18 at 04:06
  • @JohnBalvinArias talking about fetch, what's up on ie11 or even Edge ? – Ben Nov 01 '18 at 21:34
  • Correct me if I'm wrong, but fetch does not properly work on "modern" ie, and ie is still broadly used. If I were using jquery, i'd hardly be encouraged to move on then – Ben Nov 01 '18 at 23:22
  • @Ben where do you get the fact ie is broadly used? also, if you want to support ie I would argue that is better JQuery because native xhr is little bit messy, in the other hand it's a waste of time being all the time worry about if ie supports something, at least for me I just try to use the most update apis, and see if at least it is supported in chrome and in firefox – John Balvin Arias Nov 02 '18 at 01:52
  • Thus [the meme](https://meta.stackexchange.com/questions/19478/the-many-memes-of-meta/19492#19492). – Peter Mortensen May 07 '22 at 19:42
1

I think the following function can help to have scroll coordinate values:

const getScrollCoordinate = (el = window) => ({
  x: el.pageXOffset || el.scrollLeft,
  y: el.pageYOffset || el.scrollTop,
});

I got this idea from this answer with a little change.

AmerllicA
  • 29,059
  • 15
  • 130
  • 154
0

when you scroll you get the div postion

when you click on the div, the scroll bar scroll 500 in the y axis

function getTagPosition(event) {
        
  let x = document.getElementById("hi").offsetLeft

  let y = document.getElementById("hi").offsetTop

  console.log("x", x, "y", y);
         
}

function scrollToPosition(position) {

  console.log("was here")

  document.getElementById("hi").scrollTo(0, position);
  
}
 <div id="hi" onscroll="getTagPosition()" onclick="scrollToPosition(500)" style="width: 100px; height: 100px; overflow-y: scroll;">
        
        div dsgdfgf
        div dsgdfgf
         div dsgdfgf



         div dsgdfgf

          div dsgdfgf
          div dsgdfgf
          div dsgdfgf
          div dsgdfgf
          div dsgdfgf

           div dsgdfgf
           div dsgdfgf
           div dsgdfgf

            div dsgdfgf
            div dsgdfgf

            div dsgdfgf



             div dsgdfgf
              div dsgdfgf
              div dsgdfgf
              div dsgdfgf

               div dsgdfgf
    
    </div>
    
    
Kamal Zaitar
  • 101
  • 1
  • 3