Is there a robust way to determine width of element tree immediately after creating with document.createElement and placing with something.appendChild ? Element's offsetWidth or getBoundingClientRect works fine in Firefox and IE but not in Google Chrome. It only works with setTimeout but not with zero timeout. 200 milliseconds usually does it. I've read somewhere that accessing offsetWidth triggers reflow but it does not in Google Chrome v47. Maybe it is related to this bug: https://code.google.com/p/chromium/issues/detail?id=290399.
I've never had to use a timeout with clientWidth :
var div = document.createElement('div');
var body = document.querySelector('body');
body.appendChild(div);
var div_width = div.clientWidth;
div.innerHTML = div_width;
<body></body>
Can't you store the width of the element in a variabele using jQuery?
Not sure I understood your question properly but you cannot get the Element width before attaching to the DOM.
Maybe you want to do something like this:
var test = document.getElementById('test').clientWidth;
var div = document.createElement('div');
document.getElementById('container').appendChild(div).innerHTML = 'new element';
http://jsfiddle.net/andreasonny83/5ddtzaf6/
I've figured out it was because of images and I solved it by specifying fixed dimensions. (which is unpleasant for my design)
IE and Firefox do not need it, possibly they load images before returning parent element's width.
Thanks everybody for their help.
Related
I have a routine that sizes elements in a page to fit snugly within their parent. In most cases, it is working admirably, but in Firefox (JUST Firefox - Chrome, IE, etc are fine) it is fumbling on the first attempt in one particular instance - a div nested within a fieldset fails to resize on the first attempt, but succeeds on the second (and subsequent) attempts.
Each element is sized relative to its parent using the following:
function resizeChild(elem) {
// Get gutter based on margins, borders, padding, etc
var gutter = getGutter(elem); // returns obj with x and y properties
var parent = elem.parentElement;
var parentStyles = window.computedStyle(parent);
var targetWidth = (parseInt(parentStyles['width']) - gutter.x;
var widthPx = targetWidth + 'px';
// prototype.js setStyle shortcut
elem.setStyle({
width: widthPx,
maxWidth: widthPx,
minWidth: widthPx
});
}
I run this in a loop, iterating over every element with a particular CSS class.
According to the Firefox debugger, the outer element (the fieldset) is always being resized before the inner div. I can inspect the element, and see the style attributes being set appropriately. However, on the next iteration of the loop, when the parent is being evaluated (I can see in the javascript property inspector that the parent is indeed the fieldset), the value for width that is returned for the computed style is the previous, unmodified value, thus the inner div is resized incorrectly.
Can somebody shed some light on this please?
Edits after comments:
parent.clientWidth returns 0.
Not sure if this is relevant, but a parent div of the fieldset had display set to none shortly prior the resize operation being called. However, at the point at which the fieldset was resized, the display of the div was set to inline-block. I don't think this would make a difference, but then I'm not well educated on some of the particular behaviours of Firefox in this scenario.
I found a solution to this, although it's a little situational.
It seems that if the width of the parent element has been dynamically modified using prototype.js#Element.setStyle() (and, for all I know, other libraries that directly modify the style attribute), then the computedStyle() method won't reflect the change until all changes have completed.
The solution was to check to see if the parent element of the element being resized also had the CSS class that flagged the elements for resize, and if it did, get the size from the style attribute instead of using computedStyle(). Here's the full function, with modifications:
function resizeFullwidth() {
$$('*.fullWidth').each(function(elem, i) {
// Get gutter based on margins, borders, padding, etc
var gutter = getGutter(elem); // returns obj with x and y properties
var parent = elem.parentElement;
var parentStyles = (
parent.hasClassName('fullWidth')
? window.computedStyle(parent)
: parent.style);
var targetWidth = (parseInt(parentStyles['width']) - gutter.x;
var widthPx = targetWidth + 'px';
// prototype.js setStyle shortcut
elem.setStyle({
width: widthPx,
maxWidth: widthPx,
minWidth: widthPx
});
});
}
This now works correctly in all browsers :)
Thanks very much for your help, people :)
Have you tried var targetWidth = parent.clientWidth ?
See : MDN Element.clientWidth
I think I'm going mad!
I'm starting to write a little exercise for myself where I am going to have some divs that I can drag on the rightborder to increase or decrease the Div width. I also have a container Div that has a set width and I'm going to use this to determine a percentage - basically I'm going to be making some kind of bar-chart / histogram that you can edit.
I'm started writing my code and I thought I'd just make sure I could output the percentage.
Here's the perliminary code....
<style>
#container{width:500px;}
#dragDiv{border:1px solid #000;background-color:pink;width:100px;height:100px;}
</style>
</head>
<body>
<div id="container">
<div id="dragDiv"></div>
</div>
<script>
function dragOneSide(innDiv, outDiv){
if(document.getElementById(innDiv) && document.getElementById(outDiv)){
var iDiv = document.getElementById(innDiv),
oDiv = document.getElementById(outDiv);
// write out the width as a percentage
var iDivWidth = parseInt(iDiv.style.width),
oDivWidth = parseInt(oDiv.style.width);
//alert(document.getElementById("dragDiv").style.width);
iDiv.innerHTML = ((iDivWidth / oDivWidth) * 100);
}
}
window.onload = function(){
dragOneSide("dragDiv", "container");
}
</script>
Now the value in the iDiv was NaN? I found that rather odd. When trying to alert width I was getting a blank, literally an empty string! Rather odd I thought, especially as I wasn't trying to do anything complicated. I used firebug, set a breakpoint and observed the watch window. There was no value for the Div's width. I then put an inline style on the DIV like so...
<div id="container">
<div id="dragDiv" style="width:300px;">Hello World</div>
</div>
and low and behold I was now getting a value for the item! Now I don't like inline styles (who does) however I've never had this problem before and I've been using JavaScript and HTML for years - has anyone got an explaination for this? To retrieve the width not set by CSS do I have to use a different property like clientWidth?
Ps. I haven't included any of the dragging code yet so please don't point that out.
The call to style.width retrieves the style value, which isn't set.
http://jsfiddle.net/EC2HR/
See this example. Yes, you want to use clientWidth in this case.
The simplest way is to use offsetWidth property:
var iDivWidth = parseInt(iDiv.style.offsetWidth),
oDivWidth = parseInt(oDiv.style.offsetWidth);
style.width is a DOM api which returns the width of an element when it's set inline or via the element.style.width = n + "px";
So that it reacts the way you describe it is as designed.
The offsetWidth like ioseb refers to is a DOM api call which returns the amount of horizontal space an element takes up.
Beware of the many inconsistencies between browsers .
PM5544...
I'm trying to get div's width with javascript. Initially div's width is undefined, ie width depends on amount of text on it. Is it possible to get width of this kind of div? I'm trying to do it with following javascript code, but i'm getting width differerent from Chrome console when i'm inspecting div
var mydiv = document.getElementById("error_message");
var curr_width = mydiv.clientWidth;
alert(curr_width);
Thank you for your attention
use offsetWidth
clientWidth is calculated width, offsetWidth is the one in "Chrome inspect element" (i think)
also read the comments :P
While the OP doesn't specify one way or the other, if you happen to have jQuery available, you can always use this:
var curr_width = $('#error_message').width();
I managed to solve the problem! I was trying to create div directly in javascript, without defining div on html body. So inside of tag i've created
<div id="error_message" style="visibility:hidden;"></div>
and it's worked!
Final javascript code is:
document.write("<div id=\"error_message\">Wrong username or password!</div>");
var mydiv = document.getElementById("error_message");
var curr_width = mydiv.offsetWidth;
alert(curr_width);
There are plenty of examples showing how to dynamically set an iframe's height to its content. This works perfect for me. The problem I'm now having is that the content can change size without triggering onload (think hidden/expandable divs).
Is there any way to detect when the size of the iframe content has changed? This is on the same domain and no jQuery, please.
I would do this by polling regularly (maybe every 200 milliseconds, perhaps more often) using setInterval. You could then compare the size of the content to what it was last time.
var iframe = document.getElementById('myIframe'),
lastheight;
setInterval(function(){
if (iframe.document.body.scrollheight != lastheight) {
// adjust the iframe's size
lastheight = iframe.document.body.scrollheight;
}
}, 200);
For non-webkit browsers, there are a few domMutation-Events, that fire when an attribute of an element (e.g. the body element) change. See DOMSubtreeModified and more importantly DOMAttrModified.
The internet explorer does fire the onresize event even on non-windows elements.
Opera honors the domMutation Events.
Webkit on the other discarded these events as a compromise to rendering speed and javascript-performance. Thee is no other way than to check via timeout/interval the effective size of an element.
ResizeObserver worked for me:
const iframe = document.getElementById('myIframe')
const observer = new ResizeObserver(() => {
setHeight(iframe.document.body.scrollHeight);
})
observer.observe(iframe.document.body);
When writing a Javascript a function that I had gotten help from earlier, which gets the height of an element that is hidden, someone reffered me to the Prototype function getDimensions(). In the example, they set "visibility: hidden; position: absolute; display: block;", which effectively lets us measure what the clientHeight would be if it were being displayed. Then they set it all back and you can go about your business. I haven't used prototype, but I would assume that works fine. However, when I tried to mimic the same function in my own code, the use of "position: absolute;" threw off the measurement. It works fine without it, but its use is what allows us to do this for a split second without skewing the design. My version is below, any idea why it isn't working?
var objStyle = obj[objName].style;
// Record original style values
var visibility = objStyle.visibility;
//var position = objStyle.position;
var display = objStyle.display;
// Modify object for measuring
objStyle.visibility = "hidden";
//objStyle.position = "absolute";
objStyle.display = "block";
// Measure height
height = obj[objName].clientHeight;
// Fix object
objStyle.visibility = visibility;
//objStyle.position = position;
objStyle.display = display;
// Return height
return parseInt(height);
Thanks in advance for your help.
I don't know if it works while invisible, but jQuery has some options here - in particular the height function; worth a look? Based on your example, something like:
height = $(obj[objName]).height();
Are you seeing this only on a cetain browser, or on all browsers? Prototype's getDimensions() does a check for Safari (and possibly other buggy browsers), you should try putting that in your code as well and see if it fixes the issue.
It could also be due to the fact that you're using obj[objName] as opposed to document.getElementById() - AFAIK these will return slightly different objects, which could cause the inconsistency you're seeing.
I usually measure my heights with .offsetHeight, something like:
var h = document.getElementById(divname).offsetHeight;
When I need to measure something, if it has position:absolute;
I usually run into this when I have two columns and one is absolute, and the parent needs to be pushed down by the one that's absolute if that's bigger than the other one. I'll use the offsetHeight to set the parent height if it's bigger that the height of the other column.