How to get updated width of content after a css change? - javascript

I'm trying to modify the css class of my body element.
Before modifying the class, I check the scroll width of my content:
$(window.document.body).prop('scrollWidth'); // 800px
Now I modify the css class and check the scroll width again:
$(window.document.body).prop('class', someCssClassName);
$(window.document.body).prop('scrollWidth'); // still reports 800px
I know the scroll width should not be 800px after this particular change. I start a timer and keep printing the scroll width, and after a few ms I see it change to 600px.
So it seems like I can't immediately get the updated content width (or I'm misinterpreting what's going on).
Is there a way to get notified when the re-flow is complete, so that I might get the updated width?
I don't want to set a timer and keep checking, if possible.
I'm trying this in an android WebView.. browser.. . So I'm not sure if this behavior will be the same if I try in a desktop browser.
Thank you

To answer the question: accessing the scrollWidth property automatically flushes any style change (forces a reflow) and then returns the computed value. This happens synchronously, hence you don't need to "wait" for the reflow to complete -- the JS will simply freeze while the reflow happens and then return the correct scrollWidth value.
You are actually facing a very specific Blink/WebKit bug in their scrollWidth implementation regarding the body element.
I've simplified your code a bit by removing some unnecessary jQuery abstraction (fiddle):
document.body.className = 'w600px';
console.log(
document.body.scrollWidth, // Firefox: 600, Chrome: viewport width
$(document.body).width() // 600 in both browsers
);
.w600px {
width: 600px;
}
From the CSSOM element.scrollWidth spec:
3. If the element is the HTML body element, the Document is in quirks mode and the element has no associated scrolling box, return max(viewport scrolling area width, viewport width).
It seems like Chrome is not checking whether the document is in Quirks mode and returning the viewport (scrolling) width independent of the document mode.
You should open a Chromium issue in these cases.
Workarounds
It really depends on your use case. $(document.body).width() is usually fine, unless the content overflows the body element's width.
Alternatively, wrap all the page's contents inside of a div and use it to apply the class and to retrieve the scrollWidth from.

Try
function getprop( el, prop ) {
var props = window.getComputedStyle (
$(el).get(0)).getPropertyValue(prop);
return String(props);
};
console.log(getprop("body", "width"))
http://jsfiddle.net/guest271314/6uKH6/5/

Related

scrollHeight property only updates when changed content is taller

I'm observing strange behaviour with scrollHeight (or perhaps I misunderstand exactly how/when it gets updated). I noticed that when replacing content inside an "overflow:hidden" element and attempting to explicitly set its height via the scrollHeight property (so I can animate with CSS) it only adjusts to the correct height when the replaced content is taller than before. Replacing the contents with shorter (or less) content, the scrollHeight property of the element stays at the larger value. I've outlined it in a simple test below in jQuery. I'm observing this in Safari, Chrome and Firefox.
Why is this happening?
$(window).resize(function() {
$cart = $('#cart')
$cart.css('height', $cart.prop('scrollHeight'))
})

Why does $(window).width() change while the page is loading?

I noticed that my scripts were setting widths incorrectly, so I tried the following snippet:
var prev;
setInterval(function(){
if($(window).width()!=prev)
console.log(prev=$(window).width());
},1);
This printed 2 different values: 1464 and 1481. Since these are 17px apart, I'm almost certain this is caused by scrollbars. The second value is the correct value.
Why does $(window).width() change without resizing the window? Shouldn't it return the browser window's width, which should be constant?
$(window).width() returns the width of the window object excluding scrollbars (otherwise known as the viewport width). Depending on the operating system and browser, the vertical scrollbar can often subtract from the viewport width. This means you should call this function once all your content has been loaded, and you'll need to call it again if the content changes.
Putting this in the $.ready() function won't guarantee that you'll get the correct width with respect to the final page content. This is because $.ready fires when the DOM is loaded, but there might still be images/fonts that can affect the layout. It's very possible that a scrollbar can get added after you call $.ready(). The easiest solution to this problem is to place your call inside the $(window).load() function instead, as this fires when all content has been loaded, and there's nothing more to render.
Generally speaking, it's a good idea to set the width on DOM ready, window load, window resize, and any time the content changes. This can be done like so:
$(function() {
var window_width;
function set_window_width() {
window_width = $(window).width();
// do something with window_width
}
set_window_width(); // set width on DOM ready
$(window).on('load resize', set_window_width); // set width on window load and resize
function custom_load_content() {
// load / change content
set_window_width();
}
});
Most (if not all) of the time, the viewport width is what you want. You're probably using the width to perform some calculations and/or resize some elements, and this should always be relative to the viewport, because your CSS is relative to the viewport. But, if for some reason you want to get the width including scrollbars, you can use window.innerWidth instead (source).
$(window).width() is affected by the margin, border and padding.
These can change as the DOM is being loaded.
As mentioned above, make sure you are waiting until $(document).ready() before you start looking at / twiddling with the DOM objects.
More info here http://api.jquery.com/width/
In most of the cases, the window width changes with the content, so there must be some ajax call coming which changes some content of the window. You can use browser debug tool and open the network traffic window to see what comes when the window width changes, debug into the javascript file to find which part of window changes with that ajax call, this may help you to find the reason.

I want to compare between the height of scrollbar and the document height

What I want is, an example when passing the mouse on element in page, then forced to increase the height of scrollbar, in that case, I want to shows alert box.
I have used the following code
if(document.body.offsetHeight < document.body.scrollHeight ){
alert('not Equal')
}
Also I have used clientHeight function Instead of offsetHeight function,
But he does not work well except only in chrome and safari browsers.
Update....
You can not determine if the page has scrollbars using document.body, use an div container instead, it must have overflow css property and specified height and / or width. After this you can use .offsetHeight and .scrollHeight to dermine if the content is bigger than the size of the container.

Javascript clientHeight and alternatives

I am currently trying to modify a Javascript function that "slides in" a <div>. The script as it is requires you to define the height of the div, so it is mostly useless in dynamically filled <div>s. I found some text on the clientHeight property in javascript, but it would appear that it doesn't support <div>s with display set to none (which is the method used to slide the div in). That makes sense, as the height of that div in the client window is nothing.
Basically I was wondering what other methods you all know of, or if there's a way to get around the clientHeight = 0 when display: none.
Thanks!
Oh, and here's the function I'm using:
function getDivHeight(objName) {
return boxHeight = document.getElementById(objName).clientHeight;
}
A simple solution is to set it's visibility to "hidden" and it's display to "block" and measure it. However, some modern browsers will manage to update the page layout during this short time and you will get a nasty flicker. The easiest way to overcome this is to place the element in an absolutely positioned container with overflow set to "hidden".
I've had luck cloning the element, moving it offscreen, then displaying it to get the client height:
var original = document.getElementById(some_id);
var new_item = original.cloneNode(true);
document.body.appendChild(new_item); // item already hidden, so it won't show yet.
// you may wish to validate it is hidden first
new_item.style.position = "absolute";
new_item.style.left = "-1000px";
new_item.style.display = "block";
var height = new_item.clientHeight;
EDIT: Looking through the jQuery code, they do exactly what Tsvetomir Tsonev suggests. jQuery temporarily sets the style to "display: block; position: absolute; visibility: none", and then measures the height, swapping the properties back after the measurement.
So, it looks like you're stuck with having to do something hackish, whether it's cloning the node or risking having it flicker in some browsers... I like Tsvetomir's suggestion better than my initial hack as it, at least, doesn't involve cloning a node into the DOM that you don't need. Either way, the element must not be set to "display: none" in order to measure it's height. Isn't the DOM wonderful? :-)
EDIT 2: Also worth noting that, after jQuery gathers the height, it adds allowances for padding, margin and border sizes, so you may need to as well.
Yes, an element that is not displayed on the page has no dimensions.
It kind of makes sense. Consider an element that has been created and filled with a bunch of text, but not yet added to the document tree. How high is it? Depends on font-size. How big is font-size? Depends where in the document that div is inserted; its parent font-size would inherit through.
Similarly for an element with “display: none”. It's not rendered, so it has no dimensions. Couldn't we ask “how high would this be if it were ‘display: block’”? Turns out no, because if it were displayed, that in itself could change the dimensions of its parent block, and then the dimension of displayed elements would be inconsistent with the dimensions of non-displayed elements!
The typical solution is to unset “display: none”, measure the height of the element, and then immediately re-set “display: none”. The browser won't redraw in the middle of a bit of JavaScript, so you won't see a flicker on the page.
I nkow you guys solved this a long time ago but I thought I should share this since it quite tricky to get the height of a hidden div tag.
heres what I did after reading your post,
I placed the div i want to slide inside a 1px height div with overflow set to hidden.
you dont even need to set the display of the inner div to none since it is already there and if you use offsetHeight it should return the proper height for all browsers and you can use that height to slide your div up an down.
PEACE!!!
In IE you could try scrollHeight, but I'm not sure if it will work or if it is cross browser.

How to detect when the height of your page changes?

I have a javascript heavy app which has widgets like autocomplete dropdowns and tabs and so forth. Sometimes when dropdowns appear and disappear, or when you switch between tabs, it changes the height of the document. This can cause annoyances if the scrollbar appears and disappears rapidly, because it shifts the page. I would like to detect when a page changes its height, so I can fix the height to the maximum so far, so that if the scrollbar appears it won't disappear only a second later. Any suggestions?
Update: onresize won't work because that's for changes in the size of the viewport/window - I want changes in the length of the document. I hadn't known about the watch function, looks like it will work at least for FF, but IE doesn't support it.
I belive this question has already been answered on stackoverflow here:
Detect Document Height Change
Basically you have to store the current document height and keep checking for a change via a timeoutcall
The element to watch here is document.body.clientHeight (or in jquery $(document).height() )
I think you can trap "onresize" events
here is a link to the w3schools.com description
You can user resize event to trap the change of the size of window using jquery as follows:
$(window).resize(function(){
// your code to check sizes and take action
}
);
Alternately you can track the change in document (not tested)
$(document).resize(function(){
// your code to check sizes and take action
}
);
One idea would be to use the watch() method on the clientHeight property:
document.body.watch("clientHeight", function(property, oldHeight, newHeight) {
// what you want to do when the height changes
});
The function you specify will get executed whenever the specified property changes. At any point you can use the unwatch() method to get it to stop.

Categories

Resources