Cross-Browser Method to Determine Vertical Scroll Percentage in Javascript

JavascriptCross BrowserScroll

Javascript Problem Overview


How can I find out what percentage of the vertical scrollbar a user has moved through at any given point?

It's easy enough to trap the onscroll event to fire when the user scrolls down the page, but how do I find out within that event how far they have scrolled? In this case, the percentage particularly is what's important. I'm not particularly worried about a solution for IE6.

Do any of the major frameworks (Dojo, jQuery, Prototype, Mootools) expose this in a simple cross-browser compatible way?

Javascript Solutions


Solution 1 - Javascript

> Oct 2016: Fixed. Parentheses in jsbin demo were missing from answer. Oops.

Chrome, Firefox, IE9+. Live Demo on jsbin
var h = document.documentElement, 
    b = document.body,
    st = 'scrollTop',
    sh = 'scrollHeight';

var percent = (h[st]||b[st]) / ((h[sh]||b[sh]) - h.clientHeight) * 100;

As function:

function getScrollPercent() {
    var h = document.documentElement, 
		b = document.body,
	    st = 'scrollTop',
    	sh = 'scrollHeight';
    return (h[st]||b[st]) / ((h[sh]||b[sh]) - h.clientHeight) * 100;
}

If you prefer jQuery (original answer):

$(window).on('scroll', function(){
  var s = $(window).scrollTop(),
      d = $(document).height(),
      c = $(window).height();

  var scrollPercent = (s / (d - c)) * 100;
  
  console.clear();
  console.log(scrollPercent);
})

html{ height:100%; }
body{ height:300%; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Solution 2 - Javascript

I think I found a good solution that doesn't depend on any library:

/**
 * Get current browser viewpane heigtht
 */
function _get_window_height() {
    return window.innerHeight || 
           document.documentElement.clientHeight ||
           document.body.clientHeight || 0;
}

/**
 * Get current absolute window scroll position
 */
function _get_window_Yscroll() {
    return window.pageYOffset || 
           document.body.scrollTop ||
           document.documentElement.scrollTop || 0;
}

/**
 * Get current absolute document height
 */
function _get_doc_height() {
    return Math.max(
        document.body.scrollHeight || 0, 
        document.documentElement.scrollHeight || 0,
        document.body.offsetHeight || 0, 
        document.documentElement.offsetHeight || 0,
        document.body.clientHeight || 0, 
        document.documentElement.clientHeight || 0
    );
}


/**
 * Get current vertical scroll percentage
 */
function _get_scroll_percentage() {
    return (
        (_get_window_Yscroll() + _get_window_height()) / _get_doc_height()
    ) * 100;
}

Solution 3 - Javascript

This should do the trick, no libraries required:

function currentScrollPercentage()
{
    return ((document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight) * 100);
}

Solution 4 - Javascript

These worked for me perfectly in Chrome 19.0, FF12, IE9:

function getElementScrollScale(domElement){
		return domElement.scrollTop / (domElement.scrollHeight - domElement.clientHeight);
	}
	
function setElementScrollScale(domElement,scale){
		domElement.scrollTop = (domElement.scrollHeight - domElement.clientHeight) * scale;
	}

Solution 5 - Javascript

A Typescript implementation.

function getScrollPercent(event: Event): number {
  const {target} = event;
  const {documentElement, body} = target as Document;
  const {scrollTop: documentElementScrollTop, scrollHeight: documentElementScrollHeight, clientHeight} = documentElement;
  const {scrollTop: bodyScrollTop, scrollHeight: bodyScrollHeight} = body;
  const percent = (documentElementScrollTop || bodyScrollTop) / ((documentElementScrollHeight || bodyScrollHeight) - clientHeight) * 100;
  return Math.ceil(percent);
}

Solution 6 - Javascript

If you're using Dojo, you can do the following:

var vp = dijit.getViewport();
return (vp.t / (document.documentElement.scrollHeight - vp.h));

Which will return a value between 0 and 1.

Solution 7 - Javascript

This question has been here for a long time, I know, but I stumbled onto it while trying to solve the same problem. Here is how I solved it, in jQuery:

First, I wrapped the thing I wanted to scroll in a div (not semantic, but it helps). Then set the overflow and height on the wrapper.

<div class="content-wrapper" style="overflow: scroll; height:100px">
    <div class="content">Lot of content that scrolls</div>
</div>

Finally I was able to calculate the % scroll from these metrics:

var $w = $(this),
    scroll_top = $w.scrollTop(),
    total_height = $w.find(".content").height(),        
    viewable_area = $w.height(),
    scroll_percent = Math.floor((scroll_top + viewable_area) / total_height * 100);                

Here is a fiddle with working example: http://jsfiddle.net/prEGf/

Solution 8 - Javascript

Everyone has great answers, but I just needed an answer as one variable. I didn't need an event listener, I just wanted to get the scrolled percentage. This is what I got:

const scrolledPercentage = 
    window.scrollY / (document.documentElement.scrollHeight - document.documentElement.clientHeight)

document.addEventListener("scroll", function() {
  const height = window.scrollY / (document.documentElement.scrollHeight - document.documentElement.clientHeight)

  document.getElementById("height").innerHTML = `Height: ${height}`
})

.container {
  position: relative;
  height: 200vh;
}

.sticky-div {
  position: sticky;
  top: 0;
}

<!DOCType>
<html>

<head>
</head>

<body>
  <div id="container" class="container">
    <div id="height" class="sticky-div">
      Height: 0
    </div>
  </div>
</body>

Solution 9 - Javascript

First attach an event listener to some document you want to keep track

yourDocument.addEventListener("scroll", documentEventListener, false);

Then:

function documentEventListener(){
  var currentDocument  = this;
  var docsWindow       = $(currentDocument.defaultView); // This is the window holding the document
  var docsWindowHeight = docsWindow.height(); // The viewport of the wrapper window
  var scrollTop        = $(currentDocument).scrollTop(); // How much we scrolled already, in the viewport
  var docHeight        = $(currentDocument).height();    // This is the full document height.

  var howMuchMoreWeCanScrollDown = docHeight - (docsWindowHeight + scrollTop);
  var percentViewed = 100.0 * (1 - howMuchMoreWeCanScrollDown / docHeight);
  console.log("More to scroll: "+howMuchMoreWeCanScrollDown+"pixels. Percent Viewed: "+percentViewed+"%");
}

Solution 10 - Javascript

My two cents, the accepted answer in a more "modern" way. Works back to IE9 using @babel/preset-env.

// utilities.js

/**
 * @param {Function} onRatioChange The callback when the scroll ratio changes
 */
export const monitorScroll = onRatioChange => {
  const html = document.documentElement;
  const body = document.body;

  window.addEventListener('scroll', () => {
    onRatioChange(
      (html.scrollTop || body.scrollTop)
      /
      ((html.scrollHeight || body.scrollHeight) - html.clientHeight)
    );
  });
};

Usage:

// app.js
import { monitorScroll } from './utilities';

monitorScroll(ratio => {
  console.log(`${(ratio * 100).toFixed(2)}% of the page`);
});

Solution 11 - Javascript

Using jQuery

$(window).scrollTop();

will get you the scroll position, you can then work out from there what the percentage is based on the window height.

There is also a standard DOM property scrollTop that you can use like document.body.scrollTop however I'm not sure how this behaves cross-browser, I would assume if there are inconsistencies then the jQuery method accounts for these.

Solution 12 - Javascript

var maxScrollTop = messages.get(0).scrollHeight - messages.height();
var scroll = messages.scrollTop() / maxScrollTop; // [0..1]

Solution 13 - Javascript

I found a way to correct a previous answer, so it works in all cases. Tested on Chrome, Firefox and Safari.

(((document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight) || 0) * 100)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmajelbstoatView Question on Stackoverflow
Solution 1 - JavascriptPhil RickettsView Answer on Stackoverflow
Solution 2 - JavascriptEduardoView Answer on Stackoverflow
Solution 3 - JavascriptMark BellView Answer on Stackoverflow
Solution 4 - JavascripttoskeView Answer on Stackoverflow
Solution 5 - JavascriptDavidView Answer on Stackoverflow
Solution 6 - JavascriptmajelbstoatView Answer on Stackoverflow
Solution 7 - Javascripttimemachine3030View Answer on Stackoverflow
Solution 8 - Javascriptlua_python_javaView Answer on Stackoverflow
Solution 9 - JavascriptNathan BView Answer on Stackoverflow
Solution 10 - JavascriptgremoView Answer on Stackoverflow
Solution 11 - JavascriptroryfView Answer on Stackoverflow
Solution 12 - JavascriptDenis535View Answer on Stackoverflow
Solution 13 - JavascriptAlexandru RView Answer on Stackoverflow