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?
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>
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;
}
This should do the trick, no libraries required:
function currentScrollPercentage()
{
return ((document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight) * 100);
}
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;
}
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);
}
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.
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/
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>
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+"%");
}
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`);
});
I reviewed all of these up there but they use more complex approaches to solve. I found this through a mathematical formula; brief.
The formula goes Value/Total * 100. Say Total is 200 u wanna know the percentage of 100 out of 200, you do it 100/200 * 100% = 50% (the value)
pageYOffset = The vertical scroll count without including borders. When you scroll down to bottom you get the maximum count.
offsetHeight = The total height of the page including borders!
clientHeight = The height in pixels without borders but not to the end of content!
When u scroll to bottom u get pageyoffset of 1000 for example, whereas offsetHeight of 1200 and clientHeight of 200. 1200 - 200(clientheight) now u get paggeYOffset value in offsetHeight and so scrollPosition300(300 of 1000)/1000 * 100 = 30%.
`pageOffset = window.pageYOffset;
pageHeight = document.documentElement.offsetHeight;
clientHeight = document.documentElement.clientHeight;
percentage = pageOffset / (pageHeight - clientHeight) * 100 + "%";
console.log(percentage)`
The reason why we must do offsetHeight - clientHeight it is because client heights shows all the available content in px without borders, and offsetheight shows the available content including borders, whereas pageYOffset counts the scrolls made; The scrollbar is quite long to count the whole windows it counts the scrolls itself until reaches the end, the available space in scrollbar is in px pageYOffset, so to reach that number you substract offsetHeight - clientHeight to bring to the lower value of pageYOffset.
i'll update when i get on pc, please leave a comment to make it clear so i don't forget! Thanks :)
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.
var maxScrollTop = messages.get(0).scrollHeight - messages.height();
var scroll = messages.scrollTop() / maxScrollTop; // [0..1]
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)
This is a followup question to this quetsion: Get the device width in javascript.
What I'm trying to do, is get the equivalent css of #media (max-width: 600px) in JavaScript.
The accepted answer says to do the following:
var width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
Is that still correct? Will it work for all devices?
If it's correct, what's the point of checking (window.innerWidth > 0)?
I want to know if it still works. If you look at the last comment on the answer (with 6 upvotes) it says:
How does this have so many upvotes? var width = (window.innerWidth >
0) ? window.innerWidth : screen.width; returns 667 on iphone 6 AND 6
Plus. This solution does not work correctly.
You should be able to do something like this:
if (matchMedia) {
var mq = window.matchMedia("(max-width: 600px)");
mq.addListener(WidthChange);
WidthChange(mq);
}
function WidthChange(mq) {
if (mq.matches) {
//Window width is less than or equal to 600px
} else {
//Window width is greater than 600px
}
}
From your question it seems you are asking for the following (It is a trivial answer but I assume this is what you are asking):
var width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
is equivalent to:
var width;
if (window.innerWidth > 0)
{
width = window.innerWidth;
}
else
{
width = screen.width;
}
or:
var width = screen.width;
if (window.innerWidth > 0)
{
width = window.innerWidth;
}
they all do the same thing...
from your comment below you may want the following jsFiddle:
(which shows "window.innerWidth" is what you want (size of containing element) - but some browsers don't support it - so "screen.width" becomes the fallback which may not be correct as it is the width of the whole window and not just the containing element)
var width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
$('#divOutput').html('The width is:' + width + 'px <br>' +
'window.innerWidth = ' + window.innerWidth + 'px & <br>' +
'screen.width = ' + screen.width + 'px');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="divOutput"></div>
if that doesn't help maybe look at:
window.innerWidth can't work on IE7. How to fix via JS and jQuery?
im trying to get some images to resize automatically when a window resizes.
I have this working with the code below, however I would like to have a little more control over the image such as being able to set a min-height, any ideas??
also maybe wrap the images in a div so there is a little more control? Im not to good with js so any help or explanations would help
$(function() {
var $img = $(".l");
var ratio;
var offsetX = $img.offset().left;
var offsetY = $img.offset().top;
$(window).load(function () {
ratio = $img.width() / $img.height();
$(this).resize();
});
$(window).resize(function () {
var viewportWidth = window.innerWidth || document.documentElement.clientWidth;
var viewportHeight = window.innerHeight || document.documentElement.clientHeight;
var availWidth = viewportWidth - offsetX - 70;
var availHeight = viewportHeight - offsetY - 70;
if (availWidth / availHeight > ratio) {
$img.height(availHeight);
$img.width(availHeight * ratio);
}
else {
$img.width(availWidth);
$img.height(availWidth / ratio);
}
});
});
Just use CSS:
img { width: 100%; }
You can then apply height or min-height as you need.
To see it working, resize the window of this fiddle:
Example fiddle
I'm trying to find the exact height and width of a browser's viewport, but I suspect that either Mozilla or IE is giving me the wrong number. Here's my method for height:
var viewportHeight = window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight;
I haven't started on width yet but I'm guessing it's going to be something similar.
Is there a more correct way of getting this information? Ideally, I'd like the solution to work with Safari/Chrome/other browsers as well.
You might try this:
function getViewport() {
var viewPortWidth;
var viewPortHeight;
// the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight
if (typeof window.innerWidth != 'undefined') {
viewPortWidth = window.innerWidth,
viewPortHeight = window.innerHeight
}
// IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document)
else if (typeof document.documentElement != 'undefined'
&& typeof document.documentElement.clientWidth !=
'undefined' && document.documentElement.clientWidth != 0) {
viewPortWidth = document.documentElement.clientWidth,
viewPortHeight = document.documentElement.clientHeight
}
// older versions of IE
else {
viewPortWidth = document.getElementsByTagName('body')[0].clientWidth,
viewPortHeight = document.getElementsByTagName('body')[0].clientHeight
}
return [viewPortWidth, viewPortHeight];
}
( http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/ )
However, it is not even possible to get the viewport information in all browsers (e.g. IE6 in quirks mode). But the above script should do a good job :-)
You may use shorter version:
<script type="text/javascript">
<!--
function getViewportSize(){
var e = window;
var a = 'inner';
if (!('innerWidth' in window)){
a = 'client';
e = document.documentElement || document.body;
}
return { width : e[ a+'Width' ] , height : e[ a+'Height' ] }
}
//-->
</script>
I've always just used document.documentElement.clientHeight/clientWidth. I don't think you need the OR conditions in this case.
Try this..
<script type="text/javascript">
function ViewPort()
{
var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0)
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
var viewsize = w + "," + h;
alert("Your View Port Size is:" + viewsize);
}
</script>
Use this tipp: http://www.appelsiini.net/projects/viewport or that code: http://updatepanel.wordpress.com/2009/02/20/getting-the-page-and-viewport-dimensions-using-jquery/
In a web application, I have a page that contains a DIV that has an auto-width depending on the width of the browser window.
I need an auto-height for the object. The DIV starts about 300px from the top screen, and its height should make it stretch to the bottom of the browser screen. I have a max height for the container DIV, so there would have to be minimum-height for the div. I believe I can just restrict that in CSS, and use Javascript to handle the resizing of the DIV.
My javascript isn't nearly as good as it should be. Is there an easy script I could write that would do this for me?
Edit:
The DIV houses a control that does it's own overflow handling (implements its own scroll bar).
Try this simple, specific function:
function resizeElementHeight(element) {
var height = 0;
var body = window.document.body;
if (window.innerHeight) {
height = window.innerHeight;
} else if (body.parentElement.clientHeight) {
height = body.parentElement.clientHeight;
} else if (body && body.clientHeight) {
height = body.clientHeight;
}
element.style.height = ((height - element.offsetTop) + "px");
}
It does not depend on the current distance from the top of the body being specified (in case your 300px changes).
EDIT: By the way, you would want to call this on that div every time the user changed the browser's size, so you would need to wire up the event handler for that, of course.
What should happen in the case of overflow? If you want it to just get to the bottom of the window, use absolute positioning:
div {
position: absolute;
top: 300px;
bottom: 0px;
left: 30px;
right: 30px;
}
This will put the DIV 30px in from each side, 300px from the top of the screen, and flush with the bottom. Add an overflow:auto; to handle cases where the content is larger than the div.
Edit: #Whoever marked this down, an explanation would be nice... Is something wrong with the answer?
document.getElementById('myDiv').style.height = 500;
This is the very basic JS code required to adjust the height of your object dynamically. I just did this very thing where I had some auto height property, but when I add some content via XMLHttpRequest I needed to resize my parent div and this offsetheight property did the trick in IE6/7 and FF3
If I understand what you're asking, this should do the trick:
// the more standards compliant browsers (mozilla/netscape/opera/IE7) use
// window.innerWidth and window.innerHeight
var windowHeight;
if (typeof window.innerWidth != 'undefined')
{
windowHeight = window.innerHeight;
}
// IE6 in standards compliant mode (i.e. with a valid doctype as the first
// line in the document)
else if (typeof document.documentElement != 'undefined'
&& typeof document.documentElement.clientWidth != 'undefined'
&& document.documentElement.clientWidth != 0)
{
windowHeight = document.documentElement.clientHeight;
}
// older versions of IE
else
{
windowHeight = document.getElementsByTagName('body')[0].clientHeight;
}
document.getElementById("yourDiv").height = windowHeight - 300 + "px";
With minor corrections:
function rearrange()
{
var windowHeight;
if (typeof window.innerWidth != 'undefined')
{
windowHeight = window.innerHeight;
}
// IE6 in standards compliant mode (i.e. with a valid doctype as the first
// line in the document)
else if (typeof document.documentElement != 'undefined'
&& typeof document.documentElement.clientWidth != 'undefined'
&& document.documentElement.clientWidth != 0)
{
windowHeight = document.documentElement.clientHeight;
}
// older versions of IE
else
{
windowHeight = document.getElementsByTagName('body')[0].clientHeight;
}
document.getElementById("foobar").style.height = (windowHeight - document.getElementById("foobar").offsetTop - 6)+ "px";
}
Simplest I could come up...
function resizeResizeableHeight() {
$('.resizableHeight').each( function() {
$(this).outerHeight( $(this).parent().height() - ( $(this).offset().top - ( $(this).parent().offset().top + parseInt( $(this).parent().css('padding-top') ) ) ) )
});
}
Now all you have to do is add the resizableHeight class to everything you want to autosize (to it's parent).
inspired by #jason-bunting, same thing for either height or width:
function resizeElementDimension(element, doHeight) {
dim = (doHeight ? 'Height' : 'Width')
ref = (doHeight ? 'Top' : 'Left')
var x = 0;
var body = window.document.body;
if(window['inner' + dim])
x = window['inner' + dim]
else if (body.parentElement['client' + dim])
x = body.parentElement['client' + dim]
else if (body && body['client' + dim])
x = body['client' + dim]
element.style[dim.toLowerCase()] = ((x - element['offset' + ref]) + "px");
}