Confused by document dimensions in JavaScript - javascript

I am really confused by the different properties that exist in JavaScript for getting the dimensions of a document and how to get those numbers. Can someone recommend a good place to start to understand how I would get the size of the document and position stuff correctly?

I'll try to answer as simply as I can.
The Document and Viewport
In terms of geometry, there are two sets of dimensions to be aware of; the document dimensions, which reflect the entire size of the loaded page, including the content beyond the bottom of the window and the viewport dimensions, which reflect the size of the visible part of the document that is immediately displayed in the window.
When you scroll down, the viewport moves down over the document by a certain number of pixels. In other words, the viewport is the actual browser window "border" (the toolbars, menus, tabs, and so on).
The confusion comes from the fact that depending on the browser and mode, different properties are used to get the dimensions of a document and viewport, and they return different results depending on scrollbars. But we'll come back to this.
Dimensions Overview
There are a number of properties available to you from the get-go in javascript which give you different dimensions.
Screen resolution:
window.screen.width -Height
Available screen space (same as monitor resolution) minus docks, toolbars and other UI elements:
window.screen.availWidth -Height.
Document dimensions:
document.documentElement.offsetWidth -Height
Note: These numbers do not include the scrollbars.
Viewport dimensions:
window.innerWidth -Height
These numbers include the scrollbars.
This is not available in IE 8- and IE9, so if IE, test for the document.compatMode === "CSS1Compat" and if true, use document.documentElement.clientWidth -Height, and for quirks mode use document.body.clientWidth -Height.
A note about document dimensions
As per above, document.documentElement.offsetWidth/Height provides you with the actual size of the document. One caveat to this is that scrollbars work differently between browsers. For example, IE9 will always display a vertical scrollbar even if the document height is less than the viewport height. Safari/Chrome doesn't have scrollbars on OS X Lion. Chrome on PC will not display vertical scrollbars unless it needs to.
So you may bump into inconsistencies and the Scrollbar shifts content problem. Imagine you have an absolutely positioned and centred element. Because CSS calculates the "centre" relative to the document dimensions and not the viewport dimensions, when say, Google adds the scrollbars, your content may "jump" a bit to the left as the "document centre" changes. So you may need to write JS to compensate for this effect if it bothers you, or maybe someone here can write a quick JS function to calculate document dimensions with scrollbars included.
Scrollbar Position and Dimensions
While some methods in JavaScript work with document coordinates, others work with viewport coordinates, and often this is not what you want. For example, if you have an element's top edge at 20px in document coordinates, and you scroll the page down by 20px, the top edge of that element will be at 0px relative to the top viewport coordinate. So to convert between the two systems, you first need to know by how many pixels a user has scrolled the document, and then add that number to the viewport to compensate (look at example below).
I also found these helpful:
http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
http://www.quirksmode.org/mobile/viewports.html
And here's a quick cross-browser module I mucked up to help you:
var dimensions = (function(){
var dims = {};
// get screen width/height:
dims.screenWidth = function() { window.screen.width };
dims.screenHeight = function() { return window.screen.height };
// get screen width/height minus chrome:
dims.availWidth = function() { return window.screen.availWidth };
dims.availHeight = function() { return window.screen.availHeight };
// get document width/height (with-out scrollbars):
if (window.document.compatMode == "CSS1Compat"){ // if IE Standards Mode
dims.documentWidth = function() { return document.body.offsetWidth };
dims.documentHeight = function() { return document.body.offsetHeight };
}
else {
dims.documentWidth = function() { return document.documentElement.offsetWidth };
dims.documentHeight = function() { return document.documentElement.offsetHeight };
}
// get viewport width/height (with scrollbars):
if (window.innerWidth != null) {
dims.viewportWidth = function () { return window.innerWidth };
dims.viewportHeight = function () { return window.innerHeight };
}
// if IE in Standards Mode
else if (window.document.compatMode == "CSS1Compat"){
dims.viewportWidth = function () {
return window.document.documentElement.clientWidth
};
dims.viewportHeight = function () {
return window.document.documentElement.clientHeight
};
}
// get scrollbar offsets:
if (window.pageXOffset != null) {
dims.scrollXOffset = function() { return window.pageXOffset };
dims.scrollYOffset = function() { return window.pageYOffset };
}
// if IE in Standards Mode
else if (window.document.compatMode == "CSS1Compat"){
dims.scrollXOffset = function() { return document.documentElement.scrollLeft };
dims.scrollYOffset = function() { return document.documentElement.scrollTop };
}
return dims;
}());
You can for example do console.log(dimensions.viewportWidth()) to get the viewport width.
Hope this helps you :)

Related

is there anyway to manipulate viewport in javacript?

I've been trying to figure it out using javascript to modify viewport scale and its properties. after checking visualViewport API they are all read-only data. is there any way to dynamically control viewport? like scaling up or setting position of viewport. I want to scale up the viewport as if I were a pinch zoom using javascript.
I already check similar way to handle above by using meta-tag. but I need the functionality after initialization. also viewport should be moved.
This Snippet might help you.
// Store the meta element
var viewport_meta = document.getElementById('viewport-meta');
// Define our viewport meta values
var viewports = {
default: viewport_meta.getAttribute('content'),
landscape: 'width=990'
};
// Change the viewport value based on screen.width
var viewport_set = function() {
if ( screen.width > 768 )
viewport_meta.setAttribute( 'content', viewports.landscape );
else
viewport_meta.setAttribute( 'content', viewports.default );
}
// Set the correct viewport value on page load
viewport_set();
// Set the correct viewport after device orientation change or resize
window.onresize = function() {
viewport_set();
}

orientation change VS jquery events

The website: http://negativgraffiti.hu/uj/
If you jumps from one page to another, every page has a different height, but they are all in one div, just they are not visible all the time.
I'm resizing the parent div everytime to the current page's height (not the full code, just a sample):
var magassag = jQuery("#post-5");
var egymagas = jQuery(".elsofo").height();
if (i == 1) {
magassag.animate({
height: egymagas
}, 100 );
}
it's working fine, but when i test it on tablet/mobile the height is ruins when i change the orientation, and i don't know why.
Use $(window).on('resize', fn) to detect window resizing.
$(window).on('resize', function() {
// re-animate the height for the current page
});
Although this works fine for tablet resizing, it will be very inefficient for desktop users who are resizing the window with their mouse. It is good to throttle the resize callback for that reason.
// Use `throttle` from any of the various throttle libraries available.
$(window).on('resize', throttle(function() {
// re-animate the height for the current page
}));

Can't reliably detect scroll bottom between iPhone portrait and landscape modes

I'm trying to detect when a user has scrolled to the bottom of the document. My current solution works fine in desktop browsers, and with Mobile Safari in landscape mode (with a 1px variance that I can't yet explain). However, I'm getting a completely different result for Mobile Safari in landscape mode.
I have a working example here: http://dl.dropbox.com/u/5634676/checkbottom.html
The detection routine boils down to:
if ($(window).scrollTop() + $(window).height() >= $(document).height())) {
// Bottom reached
}
Can you explain the difference between the two modes and help me reliably detect when the user has scrolled to the bottom of the document?
Update
I've updated the linked example fixing the bug pointed out by theflyingbrush. The results for landscape and portrait modes are now closer together (but there is still an as yet unexplained variance of 52px). Importantly though, for both portrait and landscape modes scrolling to the bottom of the page is still not detected.
I had the same issue on IOS mobile devices. Replace 'document' with 'body' fixed my issue.
if($(window).scrollTop() + $(window).height() > $('body').height() - 200 )
Also, it is better to check if 'near' bottom of the screen.
The height of the window changes when the device orientation changes, invalidating your windowHeight var stored on doc ready. Update it by listening for the orientationchange event and recalculating the window height. Something like:
window.addEventListener("orientationchange", change);
function change(){
windowHeight = $(window).height();
}
Edit: Confusing this, because it also involves the viewport scale. Here's a link to a working version: http://appunit.co.uk/scroll
You need to account for the height of the address bar in your calculations, because $(window).scrollTop() returns 0 until the address bar is scrolled offscreen. So, add the address bar height (60px) to scrollTop to get the distance scrolled. This is made more complicated if you haven't set a viewport meta tag in your html specifying width=device-width. In that case the viewport will be scaled from 320x356 to 980x1091, and the amount of virtual height the address bar takes up is scaled also. Summary:
var scaleFactor = ($(window).height()/356).toPrecision(2);
// toPrecision(2) prevents rounding error..
var addressBarHeight = 60 * scaleFactor;
// and when calculating scrollTop
var scrollTop = addressBarHeight + $(window).scrollTop();

Listen for browser width for responsive web design?

I'm trying to make my site mobile friendly.
I want to know the browser window size so that I do something when it's narrower than 728px and something else when it's bigger.
This must take into account resizing the window on the PC as well as changing from portrait to landscape mode in a phone.
How can this be done?
As m90 suggest, if the only thing you want to do is modify the style, then you should have a look at media queries. However, if you want to do more than just modify the style, then you have to rely on JavaScript.
Plain JavaScript
The problem is that it isn't entirely straight forward to get the width of the window, it varies between browsers. So you would have to create a function, something like this (untested):
var width = 0;
function updateWindowSize() {
if (document.body && document.body.offsetWidth) {
width = document.body.offsetWidth;
}
if (document.compatMode=='CSS1Compat' &&
document.documentElement &&
document.documentElement.offsetWidth ) {
width = document.documentElement.offsetWidth;
}
if (window.innerWidth) {
width = window.innerWidth;
}
}
Then you could listen for for the window onresize event, and call the function to get the new window size everytime the window changes.
window.onresize = function(event) {
updateWindowSize();
}
jQuery
If you use jQuery, then this can be done a bit shorter, as jQuery takes care of the cross-browser-support for you behind the scenes:
var width;
$(window).resize(function() {
width = $(window).width();
});
As a warning, IE8 and lower don't support media queries or CSS3. If you don't care about IE8, go for it. Respond.js, Modernizr and others can help to support IE6-8, but it's far from perfect.

Detect if a page has a vertical scrollbar?

I just want some simple JQ/JS to check if the current page/window (not a particular element) has a vertical scrollbar.
Googling gives me stuff that seems overly complex for just this basic feature.
How can this be done?
$(document).ready(function() {
// Check if body height is higher than window height :)
if ($("body").height() > $(window).height()) {
alert("Vertical Scrollbar! D:");
}
// Check if body width is higher than window width :)
if ($("body").width() > $(window).width()) {
alert("Horizontal Scrollbar! D:<");
}
});
try this:
var hasVScroll = document.body.scrollHeight > document.body.clientHeight;
This will only tell you if the vertical scrollHeight is bigger than the height of the viewable content, however. The hasVScroll variable will contain true or false.
If you need to do a more thorough check, add the following to the code above:
// Get the computed style of the body element
var cStyle = document.body.currentStyle||window.getComputedStyle(document.body, "");
// Check the overflow and overflowY properties for "auto" and "visible" values
hasVScroll = cStyle.overflow == "visible"
|| cStyle.overflowY == "visible"
|| (hasVScroll && cStyle.overflow == "auto")
|| (hasVScroll && cStyle.overflowY == "auto");
I tried the previous answer and doesn't seem to be working the $("body").height() does not necessarily represent the whole html height.
I have corrected the solution as follows:
// Check if body height is higher than window height :)
if ($(document).height() > $(window).height()) {
alert("Vertical Scrollbar! D:");
}
// Check if body width is higher than window width :)
if ($(document).width() > $(window).width()) {
alert("Horizontal Scrollbar! D:<");
}
Let's bring this question back from the dead ;) There is a reason Google doesn't give you a simple solution. Special cases and browser quirks affect the calculation, and it is not as trivial as it seems to be.
Unfortunately, there are problems with the solutions outlined here so far. I don't mean to disparage them at all - they are great starting points and touch on all the key properties needed for a more robust approach. But I wouldn't recommend copying and pasting the code from any of the other answers because
they don't capture the effect of positioned content in a way that is reliable cross-browser. The answers which are based on body size miss this entirely (the body is not the offset parent of such content unless it is positioned itself). And those answers checking $( document ).width() and .height() fall prey to jQuery's buggy detection of document size.
Relying on window.innerWidth, if the browser supports it, makes your code fail to detect scroll bars in mobile browsers, where the width of the scroll bar is generally 0. They are just shown temporarily as an overlay and don't take up space in the document. Zooming on mobile also becomes a problem that way (long story).
The detection can be thrown off when people explicitly set the overflow of both the html and body element to non-default values (what happens then is a little involved - see this description).
In most answers, body padding, borders or margins are not detected and distort the results.
I have spent more time than I would have imagined on a finding a solution that "just works" (cough). The algorithm I have come up with is now part of a plugin, jQuery.isInView, which exposes a .hasScrollbar method. Have a look at the source if you wish.
In a scenario where you are in full control of the page and don't have to deal with unknown CSS, using a plugin may be overkill - after all, you know which edge cases apply, and which don't. However, if you need reliable results in an unknown environment, then I don't think the solutions outlined here will be enough. You are better off using a well-tested plugin - mine or anybody elses.
This one did works for me:
function hasVerticalScroll(node){
if(node == undefined){
if(window.innerHeight){
return document.body.offsetHeight> window.innerHeight;
}
else {
return document.documentElement.scrollHeight >
document.documentElement.offsetHeight ||
document.body.scrollHeight>document.body.offsetHeight;
}
}
else {
return node.scrollHeight> node.offsetHeight;
}
}
For the body, just use hasVerticalScroll().
let hasScrollbar = window.innerWidth > document.documentElement.clientWidth;
Oddly none of these solutions tell you if a page has a vertical scrollbar.
window.innerWidth - document.body.clientWidth will give you the width of the scrollbar. This should work in anything IE9+ (not tested in the lesser browsers). (Or to strictly answer the question, !!(window.innerWidth - document.body.clientWidth)
Why? Let's say you have a page where the content is taller than the window height and the user can scroll up/down. If you're using Chrome on a Mac with no mouse plugged in, the user will not see a scrollbar. Plug a mouse in and a scrollbar will appear. (Note this behaviour can be overridden, but that's the default AFAIK).
<script>
var scrollHeight = document.body.scrollHeight;
var clientHeight = document.documentElement.clientHeight;
var hasVerticalScrollbar = scrollHeight > clientHeight;
alert(scrollHeight + " and " + clientHeight); //for checking / debugging.
alert("hasVerticalScrollbar is " + hasVerticalScrollbar + "."); //for checking / debugging.
</script>
This one will tell you if you have a scrollbar or not. I've included some information that may help with debugging, which will display as a JavaScript alert.
Put this in a script tag, after the closing body tag.
I found vanila solution
var hasScrollbar = function() {
// The Modern solution
if (typeof window.innerWidth === 'number')
return window.innerWidth > document.documentElement.clientWidth
// rootElem for quirksmode
var rootElem = document.documentElement || document.body
// Check overflow style property on body for fauxscrollbars
var overflowStyle
if (typeof rootElem.currentStyle !== 'undefined')
overflowStyle = rootElem.currentStyle.overflow
overflowStyle = overflowStyle || window.getComputedStyle(rootElem, '').overflow
// Also need to check the Y axis overflow
var overflowYStyle
if (typeof rootElem.currentStyle !== 'undefined')
overflowYStyle = rootElem.currentStyle.overflowY
overflowYStyle = overflowYStyle || window.getComputedStyle(rootElem, '').overflowY
var contentOverflows = rootElem.scrollHeight > rootElem.clientHeight
var overflowShown = /^(visible|auto)$/.test(overflowStyle) || /^(visible|auto)$/.test(overflowYStyle)
var alwaysShowScroll = overflowStyle === 'scroll' || overflowYStyle === 'scroll'
return (contentOverflows && overflowShown) || (alwaysShowScroll)
}
I use
function windowHasScroll()
{
return document.body.clientHeight > document.documentElement.clientHeight;
}
Simply compare the width of the documents root element (i.e. html element) against the inner portion of the window:
if ((window.innerWidth - document.documentElement.clientWidth) >0) console.log('V-scrollbar active')
If you also need to know the scrollbar width:
vScrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
Other solutions didn't work in one of my projects and I've ending up checking overflow css property
function haveScrollbar() {
var style = window.getComputedStyle(document.body);
return style["overflow-y"] != "hidden";
}
but it will only work if scrollbar appear disappear by changing the prop it will not work if the content is equal or smaller than the window.
I wrote an updated version of Kees C. Bakker's answer:
const hasVerticalScroll = (node) => {
if (!node) {
if (window.innerHeight) {
return document.body.offsetHeight > window.innerHeight
}
return (document.documentElement.scrollHeight > document.documentElement.offsetHeight)
|| (document.body.scrollHeight > document.body.offsetHeight)
}
return node.scrollHeight > node.offsetHeight
}
if (hasVerticalScroll(document.querySelector('body'))) {
this.props.handleDisableDownScrollerButton()
}
The function returns true or false depending whether the page has a vertical scrollbar or not.
For example:
const hasVScroll = hasVerticalScroll(document.querySelector('body'))
if (hasVScroll) {
console.log('HAS SCROLL', hasVScroll)
}

Categories

Resources