Javascript clientHeight inconsistency - javascript

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.

Related

How to obtain effective iframe height [duplicate]

How do you get the rendered height of an element?
Let's say you have a <div> element with some content inside. This content inside is going to stretch the height of the <div>. How do you get the "rendered" height when you haven't explicitly set the height. Obviously, I tried:
var h = document.getElementById('someDiv').style.height;
Is there a trick for doing this? I am using jQuery if that helps.
Try one of:
var h = document.getElementById('someDiv').clientHeight;
var h = document.getElementById('someDiv').offsetHeight;
var h = document.getElementById('someDiv').scrollHeight;
clientHeight includes the height and vertical padding.
offsetHeight includes the height, vertical padding, and vertical borders.
scrollHeight includes the height of the contained document (would be greater than just height in case of scrolling), vertical padding, and vertical borders.
It should just be
$('#someDiv').height();
with jQuery. This retrieves the height of the first item in the wrapped set as a number.
Trying to use
.style.height
only works if you have set the property in the first place. Not very useful!
NON JQUERY since there were a bunch of links using elem.style.height in the top of these answers...
INNER HEIGHT:
https://developer.mozilla.org/en-US/docs/Web/API/Element.clientHeight
document.getElementById(id_attribute_value).clientHeight;
OUTER HEIGHT:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement.offsetHeight
document.getElementById(id_attribute_value).offsetHeight;
Or one of my favorite references: http://youmightnotneedjquery.com/
I use this to get the height of an element (returns float):
document.getElementById('someDiv').getBoundingClientRect().height
It also works when you use the virtual DOM. I use it in Vue like this:
this.$refs['some-ref'].getBoundingClientRect().height
For a Vue component:
this.$refs['some-ref'].$el.getBoundingClientRect().height
You can use .outerHeight() for this purpose.
It will give you full rendered height of the element. Also, you don't need to set any css-height of the element. For precaution you can keep its height auto so it can be rendered as per content's height.
//if you need height of div excluding margin/padding/border
$('#someDiv').height();
//if you need height of div with padding but without border + margin
$('#someDiv').innerHeight();
// if you need height of div including padding and border
$('#someDiv').outerHeight();
//and at last for including border + margin + padding, can use
$('#someDiv').outerHeight(true);
For a clear view of these function you can go for jQuery's site or a detailed post here.
it will clear the difference between .height() / innerHeight() / outerHeight()
style = window.getComputedStyle(your_element);
then simply: style.height
Definitely use
$('#someDiv').height() // to read it
or
$('#someDiv').height(newHeight) // to set it
I'm posting this as an additional answer because theres a couple important things I just learnt.
I almost fell into the trap just now of using offsetHeight. This is what happened :
I used the good old trick of using a debugger to 'watch' what properties my element has
I saw which one has a value around the value I was expecting
It was offsetHeight - so I used that.
Then i realized it didnt work with a hidden DIV
I tried hiding after calculating maxHeight but that looked clumsy - got in a mess.
I did a search - discovered jQuery.height() - and used it
found out height() works even on hidden elements
just for fun I checked the jQuery implementation of height/width
Here's just a portion of it :
Math.max(
Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]),
Math.max(document.body["offset" + name], document.documentElement["offset" + name])
)
Yup it looks at BOTH scroll and offset. If that fails it looks even further, taking into account browser and css compatibility issues. In other words STUFF I DONT CARE ABOUT - or want to.
But I dont have to. Thanks jQuery!
Moral of the story : if jQuery has a method for something its probably for a good reason, likely related to compatibilty.
If you haven't read through the jQuery list of methods recently I suggest you take a look.
I think the best way to do this in 2020 is to use vanilla js and getBoundingClientRect().height;
Here's an example
let div = document.querySelector('div');
let divHeight = div.getBoundingClientRect().height;
console.log(`Div Height: ${divHeight}`);
<div>
How high am I? šŸ„“
</div>
On top of getting height this way, we also have access to a bunch of other stuff about the div.
let div = document.querySelector('div');
let divInfo = div.getBoundingClientRect();
console.log(divInfo);
<div>What else am I? šŸ„“</div>
I made a simple code that doesn't even need JQuery and probably gonna help some people.
It gets the total height of 'ID1' after loaded and use it on 'ID2'
function anyName(){
var varname=document.getElementById('ID1').offsetHeight;
document.getElementById('ID2').style.height=varname+'px';
}
Then just set the body to load it
<body onload='anyName()'>
document.querySelector('.project_list_div').offsetHeight;
Hm we can get the Element geometry...
var geometry;
geometry={};
var element=document.getElementById(#ibims);
var rect = element.getBoundingClientRect();
this.geometry.top=rect.top;
this.geometry.right=rect.right;
this.geometry.bottom=rect.bottom;
this.geometry.left=rect.left;
this.geometry.height=this.geometry.bottom-this.geometry.top;
this.geometry.width=this.geometry.right-this.geometry.left;
console.log(this.geometry);
How about this plain JS ?
So is this the answer?
"If you need to calculate something but not show it, set the element to visibility:hidden and position:absolute, add it to the DOM tree, get the offsetHeight, and remove it. (That's what the prototype library does behind the lines last time I checked)."
I have the same problem on a number of elements. There is no jQuery or Prototype to be used on the site but I'm all in favor of borrowing the technique if it works. As an example of some things that failed to work, followed by what did, I have the following code:
// Layout Height Get
function fnElementHeightMaxGet(DoScroll, DoBase, elementPassed, elementHeightDefault)
{
var DoOffset = true;
if (!elementPassed) { return 0; }
if (!elementPassed.style) { return 0; }
var thisHeight = 0;
var heightBase = parseInt(elementPassed.style.height);
var heightOffset = parseInt(elementPassed.offsetHeight);
var heightScroll = parseInt(elementPassed.scrollHeight);
var heightClient = parseInt(elementPassed.clientHeight);
var heightNode = 0;
var heightRects = 0;
//
if (DoBase) {
if (heightBase > thisHeight) { thisHeight = heightBase; }
}
if (DoOffset) {
if (heightOffset > thisHeight) { thisHeight = heightOffset; }
}
if (DoScroll) {
if (heightScroll > thisHeight) { thisHeight = heightScroll; }
}
//
if (thisHeight == 0) { thisHeight = heightClient; }
//
if (thisHeight == 0) {
// Dom Add:
// all else failed so use the protype approach...
var elBodyTempContainer = document.getElementById('BodyTempContainer');
elBodyTempContainer.appendChild(elementPassed);
heightNode = elBodyTempContainer.childNodes[0].offsetHeight;
elBodyTempContainer.removeChild(elementPassed);
if (heightNode > thisHeight) { thisHeight = heightNode; }
//
// Bounding Rect:
// Or this approach...
var clientRects = elementPassed.getClientRects();
heightRects = clientRects.height;
if (heightRects > thisHeight) { thisHeight = heightRects; }
}
//
// Default height not appropriate here
// if (thisHeight == 0) { thisHeight = elementHeightDefault; }
if (thisHeight > 3000) {
// ERROR
thisHeight = 3000;
}
return thisHeight;
}
which basically tries anything and everything only to get a zero result. ClientHeight with no affect. With the problem elements I typically get NaN in the Base and zero in the Offset and Scroll heights. I then tried the Add DOM solution and clientRects to see if it works here.
29 Jun 2011,
I did indeed update the code to try both adding to DOM and clientHeight with better results than I expected.
1) clientHeight was also 0.
2) Dom actually gave me a height which was great.
3) ClientRects returns a result almost identical to the DOM technique.
Because the elements added are fluid in nature, when they are added to an otherwise empty DOM Temp element they are rendered according to the width of that container. This get weird, because that is 30px shorter than it eventually ends up.
I added a few snapshots to illustrate how the height is calculated differently.
The height differences are obvious. I could certainly add absolute positioning and hidden but I am sure that will have no effect. I continued to be convinced this would not work!
(I digress further) The height comes out (renders) lower than the true rendered height. This could be addressed by setting the width of the DOM Temp element to match the existing parent and could be done fairly accurately in theory. I also do not know what would result from removing them and adding them back into their existing location. As they arrived through an innerHTML technique I will be looking using this different approach.
* HOWEVER * None of that was necessary. In fact it worked as advertised and returned the correct height!!!
When I was able to get the menus visible again amazingly DOM had returned the correct height per the fluid layout at the top of the page (279px). The above code also uses getClientRects which return 280px.
This is illustrated in the following snapshot (taken from Chrome once working.)
Now I have noooooo idea why that prototype trick works, but it seems to. Alternatively, getClientRects also works.
I suspect the cause of all this trouble with these particular elements was the use of innerHTML instead of appendChild, but that is pure speculation at this point.
offsetHeight, usually.
If you need to calculate something but not show it, set the element to visibility:hidden and position:absolute, add it to the DOM tree, get the offsetHeight, and remove it. (That's what the prototype library does behind the scenes last time I checked).
Sometimes offsetHeight will return zero because the element you've created has not been rendered in the Dom yet. I wrote this function for such circumstances:
function getHeight(element)
{
var e = element.cloneNode(true);
e.style.visibility = "hidden";
document.body.appendChild(e);
var height = e.offsetHeight + 0;
document.body.removeChild(e);
e.style.visibility = "visible";
return height;
}
If you are using jQuery already, your best bet is .outerHeight() or .height(), as has been stated.
Without jQuery, you can check the box-sizing in use and add up various paddings + borders + clientHeight, or you can use getComputedStyle:
var h = getComputedStyle(document.getElementById('someDiv')).height;
h will now be a string like a "53.825px".
And I can't find the reference, but I think I heard getComputedStyle() can be expensive, so it's probably not something you want to call on each window.onscroll event (but then, neither is jQuery's height()).
With MooTools:
$('someDiv').getSize().y
If i understood your question correctly, then maybe something like this would help:
function testDistance(node1, node2) {
/* get top position of node 1 */
let n1Pos = node1.offsetTop;
/* get height of node 1 */
let n1Height = node1.clientHeight;
/* get top position of node 2 */
let n2Pos = node2.offsetTop;
/* get height of node 2 */
let n2Height = node2.clientHeight;
/* add height of both nodes */
let heightTogether = n1Height + n2Height;
/* calculate distance from top of node 1 to bottom of node 2 */
let actualDistance = (n2Pos + n2Height) - n1Pos;
/* if the distance between top of node 1 and bottom of node 2
is bigger than their heights combined, than there is something between them */
if (actualDistance > heightTogether) {
/* do something here if they are not together */
console.log('they are not together');
} else {
/* do something here if they are together */
console.log('together');
}
}
Have you set the height in the css specifically? If you haven't you need to use offsetHeight; rather than height
var h = document.getElementById('someDiv').style.offsetHeight;

get and set height of element [duplicate]

How do you get the rendered height of an element?
Let's say you have a <div> element with some content inside. This content inside is going to stretch the height of the <div>. How do you get the "rendered" height when you haven't explicitly set the height. Obviously, I tried:
var h = document.getElementById('someDiv').style.height;
Is there a trick for doing this? I am using jQuery if that helps.
Try one of:
var h = document.getElementById('someDiv').clientHeight;
var h = document.getElementById('someDiv').offsetHeight;
var h = document.getElementById('someDiv').scrollHeight;
clientHeight includes the height and vertical padding.
offsetHeight includes the height, vertical padding, and vertical borders.
scrollHeight includes the height of the contained document (would be greater than just height in case of scrolling), vertical padding, and vertical borders.
It should just be
$('#someDiv').height();
with jQuery. This retrieves the height of the first item in the wrapped set as a number.
Trying to use
.style.height
only works if you have set the property in the first place. Not very useful!
NON JQUERY since there were a bunch of links using elem.style.height in the top of these answers...
INNER HEIGHT:
https://developer.mozilla.org/en-US/docs/Web/API/Element.clientHeight
document.getElementById(id_attribute_value).clientHeight;
OUTER HEIGHT:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement.offsetHeight
document.getElementById(id_attribute_value).offsetHeight;
Or one of my favorite references: http://youmightnotneedjquery.com/
I use this to get the height of an element (returns float):
document.getElementById('someDiv').getBoundingClientRect().height
It also works when you use the virtual DOM. I use it in Vue like this:
this.$refs['some-ref'].getBoundingClientRect().height
For a Vue component:
this.$refs['some-ref'].$el.getBoundingClientRect().height
You can use .outerHeight() for this purpose.
It will give you full rendered height of the element. Also, you don't need to set any css-height of the element. For precaution you can keep its height auto so it can be rendered as per content's height.
//if you need height of div excluding margin/padding/border
$('#someDiv').height();
//if you need height of div with padding but without border + margin
$('#someDiv').innerHeight();
// if you need height of div including padding and border
$('#someDiv').outerHeight();
//and at last for including border + margin + padding, can use
$('#someDiv').outerHeight(true);
For a clear view of these function you can go for jQuery's site or a detailed post here.
it will clear the difference between .height() / innerHeight() / outerHeight()
style = window.getComputedStyle(your_element);
then simply: style.height
Definitely use
$('#someDiv').height() // to read it
or
$('#someDiv').height(newHeight) // to set it
I'm posting this as an additional answer because theres a couple important things I just learnt.
I almost fell into the trap just now of using offsetHeight. This is what happened :
I used the good old trick of using a debugger to 'watch' what properties my element has
I saw which one has a value around the value I was expecting
It was offsetHeight - so I used that.
Then i realized it didnt work with a hidden DIV
I tried hiding after calculating maxHeight but that looked clumsy - got in a mess.
I did a search - discovered jQuery.height() - and used it
found out height() works even on hidden elements
just for fun I checked the jQuery implementation of height/width
Here's just a portion of it :
Math.max(
Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]),
Math.max(document.body["offset" + name], document.documentElement["offset" + name])
)
Yup it looks at BOTH scroll and offset. If that fails it looks even further, taking into account browser and css compatibility issues. In other words STUFF I DONT CARE ABOUT - or want to.
But I dont have to. Thanks jQuery!
Moral of the story : if jQuery has a method for something its probably for a good reason, likely related to compatibilty.
If you haven't read through the jQuery list of methods recently I suggest you take a look.
I think the best way to do this in 2020 is to use vanilla js and getBoundingClientRect().height;
Here's an example
let div = document.querySelector('div');
let divHeight = div.getBoundingClientRect().height;
console.log(`Div Height: ${divHeight}`);
<div>
How high am I? šŸ„“
</div>
On top of getting height this way, we also have access to a bunch of other stuff about the div.
let div = document.querySelector('div');
let divInfo = div.getBoundingClientRect();
console.log(divInfo);
<div>What else am I? šŸ„“</div>
I made a simple code that doesn't even need JQuery and probably gonna help some people.
It gets the total height of 'ID1' after loaded and use it on 'ID2'
function anyName(){
var varname=document.getElementById('ID1').offsetHeight;
document.getElementById('ID2').style.height=varname+'px';
}
Then just set the body to load it
<body onload='anyName()'>
document.querySelector('.project_list_div').offsetHeight;
Hm we can get the Element geometry...
var geometry;
geometry={};
var element=document.getElementById(#ibims);
var rect = element.getBoundingClientRect();
this.geometry.top=rect.top;
this.geometry.right=rect.right;
this.geometry.bottom=rect.bottom;
this.geometry.left=rect.left;
this.geometry.height=this.geometry.bottom-this.geometry.top;
this.geometry.width=this.geometry.right-this.geometry.left;
console.log(this.geometry);
How about this plain JS ?
So is this the answer?
"If you need to calculate something but not show it, set the element to visibility:hidden and position:absolute, add it to the DOM tree, get the offsetHeight, and remove it. (That's what the prototype library does behind the lines last time I checked)."
I have the same problem on a number of elements. There is no jQuery or Prototype to be used on the site but I'm all in favor of borrowing the technique if it works. As an example of some things that failed to work, followed by what did, I have the following code:
// Layout Height Get
function fnElementHeightMaxGet(DoScroll, DoBase, elementPassed, elementHeightDefault)
{
var DoOffset = true;
if (!elementPassed) { return 0; }
if (!elementPassed.style) { return 0; }
var thisHeight = 0;
var heightBase = parseInt(elementPassed.style.height);
var heightOffset = parseInt(elementPassed.offsetHeight);
var heightScroll = parseInt(elementPassed.scrollHeight);
var heightClient = parseInt(elementPassed.clientHeight);
var heightNode = 0;
var heightRects = 0;
//
if (DoBase) {
if (heightBase > thisHeight) { thisHeight = heightBase; }
}
if (DoOffset) {
if (heightOffset > thisHeight) { thisHeight = heightOffset; }
}
if (DoScroll) {
if (heightScroll > thisHeight) { thisHeight = heightScroll; }
}
//
if (thisHeight == 0) { thisHeight = heightClient; }
//
if (thisHeight == 0) {
// Dom Add:
// all else failed so use the protype approach...
var elBodyTempContainer = document.getElementById('BodyTempContainer');
elBodyTempContainer.appendChild(elementPassed);
heightNode = elBodyTempContainer.childNodes[0].offsetHeight;
elBodyTempContainer.removeChild(elementPassed);
if (heightNode > thisHeight) { thisHeight = heightNode; }
//
// Bounding Rect:
// Or this approach...
var clientRects = elementPassed.getClientRects();
heightRects = clientRects.height;
if (heightRects > thisHeight) { thisHeight = heightRects; }
}
//
// Default height not appropriate here
// if (thisHeight == 0) { thisHeight = elementHeightDefault; }
if (thisHeight > 3000) {
// ERROR
thisHeight = 3000;
}
return thisHeight;
}
which basically tries anything and everything only to get a zero result. ClientHeight with no affect. With the problem elements I typically get NaN in the Base and zero in the Offset and Scroll heights. I then tried the Add DOM solution and clientRects to see if it works here.
29 Jun 2011,
I did indeed update the code to try both adding to DOM and clientHeight with better results than I expected.
1) clientHeight was also 0.
2) Dom actually gave me a height which was great.
3) ClientRects returns a result almost identical to the DOM technique.
Because the elements added are fluid in nature, when they are added to an otherwise empty DOM Temp element they are rendered according to the width of that container. This get weird, because that is 30px shorter than it eventually ends up.
I added a few snapshots to illustrate how the height is calculated differently.
The height differences are obvious. I could certainly add absolute positioning and hidden but I am sure that will have no effect. I continued to be convinced this would not work!
(I digress further) The height comes out (renders) lower than the true rendered height. This could be addressed by setting the width of the DOM Temp element to match the existing parent and could be done fairly accurately in theory. I also do not know what would result from removing them and adding them back into their existing location. As they arrived through an innerHTML technique I will be looking using this different approach.
* HOWEVER * None of that was necessary. In fact it worked as advertised and returned the correct height!!!
When I was able to get the menus visible again amazingly DOM had returned the correct height per the fluid layout at the top of the page (279px). The above code also uses getClientRects which return 280px.
This is illustrated in the following snapshot (taken from Chrome once working.)
Now I have noooooo idea why that prototype trick works, but it seems to. Alternatively, getClientRects also works.
I suspect the cause of all this trouble with these particular elements was the use of innerHTML instead of appendChild, but that is pure speculation at this point.
offsetHeight, usually.
If you need to calculate something but not show it, set the element to visibility:hidden and position:absolute, add it to the DOM tree, get the offsetHeight, and remove it. (That's what the prototype library does behind the scenes last time I checked).
Sometimes offsetHeight will return zero because the element you've created has not been rendered in the Dom yet. I wrote this function for such circumstances:
function getHeight(element)
{
var e = element.cloneNode(true);
e.style.visibility = "hidden";
document.body.appendChild(e);
var height = e.offsetHeight + 0;
document.body.removeChild(e);
e.style.visibility = "visible";
return height;
}
If you are using jQuery already, your best bet is .outerHeight() or .height(), as has been stated.
Without jQuery, you can check the box-sizing in use and add up various paddings + borders + clientHeight, or you can use getComputedStyle:
var h = getComputedStyle(document.getElementById('someDiv')).height;
h will now be a string like a "53.825px".
And I can't find the reference, but I think I heard getComputedStyle() can be expensive, so it's probably not something you want to call on each window.onscroll event (but then, neither is jQuery's height()).
With MooTools:
$('someDiv').getSize().y
If i understood your question correctly, then maybe something like this would help:
function testDistance(node1, node2) {
/* get top position of node 1 */
let n1Pos = node1.offsetTop;
/* get height of node 1 */
let n1Height = node1.clientHeight;
/* get top position of node 2 */
let n2Pos = node2.offsetTop;
/* get height of node 2 */
let n2Height = node2.clientHeight;
/* add height of both nodes */
let heightTogether = n1Height + n2Height;
/* calculate distance from top of node 1 to bottom of node 2 */
let actualDistance = (n2Pos + n2Height) - n1Pos;
/* if the distance between top of node 1 and bottom of node 2
is bigger than their heights combined, than there is something between them */
if (actualDistance > heightTogether) {
/* do something here if they are not together */
console.log('they are not together');
} else {
/* do something here if they are together */
console.log('together');
}
}
Have you set the height in the css specifically? If you haven't you need to use offsetHeight; rather than height
var h = document.getElementById('someDiv').style.offsetHeight;

Getting the computed width of an element after modification

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

How do I get the height of a textarea

I need to get the height of a textarea. Seemingly so simple but it's driving me mad.
I have been researching for ages on stackoverflow with no luck: textarea-value-height and jquery-js-get-the-scrollbar-height-of-an-textarea and javascript-how-to-get-the-height-of-text-inside-of-a-textarea, among many others.
This is how it looks currently:
This is how I want it to look, open a full height:
.
Here is my html:
<textarea id="history" class="input-xxlarge" placeholder="Enter the content ..." rows="13"></textarea>
CSS:
.input-xxlarge {
display: inline-block;
height: auto;
font-size: 12px;
width: 530px;
resize: none;
overflow: auto;
}
jQuery:
var textarea = $('#history');
I've tried (inter alia):
1. textarea.height() --> always returns 0
2. textarea.ready(function() { // wait for DOM to load
textarea.height();
}
3. getting scrollheight from textarea as an HTMLTextareaElement (i.e. DOM Element) --> returns 0
4. var contentSpan = textarea.wrapInner('<span>');
var height = contentSpan.height(); --> always returns 0
Please help, I'm at my wit's end!
Ok, I've found a solution. Whether it's the best solution, I don't know, but it works and that, frankly, is all I care about, having spent almost a day on this issue.
Here it is for anyone who faces the same problem:
Select the textarea:
var textarea = $('#history');
Get the textarea's text:
var text = textarea.text();
Create a temporary div:
var div = $('<div id="temp"></div>');
Set the temp div's width to be the same as the textarea. Very important else the text will be all on one line in the new temp div!:
div.css({
"width":"530px"
});
Insert the text into the new temp div:
div.text(text);
Append it to the DOM:
$('body').append(div);
Get the height of the div:
var divHeight = $('#temp').height();
Remove the temp div from the DOM:
div.remove();
Had a similar issue, in my case I wanted to have an expand button, that would toggle between two states (expanded/collapsed). After searching also for hours I finally came up with this solution:
Use the .prop to get the content height - works with dynamically filled textareas and then on a load command set it to your textarea.
Get the inner height:
var innerHeight = $('#MyTextarea').prop('scrollHeight');
Set it to your element
$('#MyTextarea').height(innerHeight);
Complete code with my expand button(I had min-height set on my textarea):
$(document).on("click", '.expand-textarea', function () {
$(this).toggleClass('Expanded');
if($(this).hasClass('Expanded'))
$($(this).data('target')).height(1);
else
$($(this).data('target')).height($($(this).data('target')).prop('scrollHeight'));
});
Modern answer: textarea sizing is a few lines of ES6 implementable two primary ways. It does not require (or benefit from) jQuery, nor does it require duplication of the content being sized.
As this is most often required to implement the functionality of auto-sizing, the code given below implements this feature. If your modal dialog containing the text area is not artificially constrained, but can adapt to the inner content size, this can be a perfect solution. E.g. don't specify the modal body's height and remove overflow-y directives. (Then no JS will be required to adjust the modal height at all.)
See the final section for additional details if you really, truly only actually need to fetch the height, not adapt the height of the textarea itself.
Lineā€“Based
Pro: almost trivial. Pro: exploits existing user-agent behavior which does the heavy lifting (font metric calculations) for you. Con: impossible to animate. Con: extended to support constraints as per my codepen used to explore this problem, constraints are encoded into the HTML, not part of the CSS, as data attributes.
/* Lines must not wrap using this technique. */
textarea { overflow-x: auto; white-space: nowrap; resize: none }
for ( let elem of document.getElementsByTagName('textarea') ) {
// Prevent "jagged flashes" as lines are added.
elem.addEventListener('keydown', e => if ( e.which === 13 ) e.target.rows = e.target.rows + 1)
// React to the finalization of keyboard entry.
elem.addEventListener('keyup', e => e.target.rows = (elem.value.match(/\n/g) || "").length + 1)
}
Scrollable Regionā€“Based
Pro: still almost trivial. Pro: animatable in CSS (i.e. using transition), though with some mild difficulty relating to collapsing back down. Pro: constraints defined in CSS through min-height and max-height. Con: unless carefully calculated, constraints may crop lines.
for ( let elem of document.getElementsByTagName('textarea') )
elem.addEventListener('keyup', e => {
e.target.style.height = 0 // SEE NOTE
e.target.style.height = e.target.scrollHeight + 'px'
})
A shocking percentage of the search results utilizing scrollHeight never consider the case of reducing size; for details, see below. Or they utilize events "in the wrong order" resulting in an apparent delay between entry and update, e.g. pressing enterā€¦ then any other key in order to update. Example.
Solution to Initial Question
The initial question specifically related to fetching the height of a textarea. The second approach to auto-sizing, there, demonstrates the solution to that specific question in relation to the actual content. scrollHeight contains the height of the element regardless of constraint, e.g. its inner content size.
Note: scrollHeight is technically the Math.max() of the element's outer height or the inner height, whichever is larger. Thus the initial assignment of zero height. Without this, the textarea would expand, but never collapse. Initial assignment of zero ensures you retrieve the actual inner content height. For sampling without alteration, remove the height override (assign '') or preserve (prior to) then restore after retrieval of scrolllHeight.
To calculate just the height of the element as-is, utilize getComputedStyle and parse the result:
parseInt(getComputedStyle(elem).height, 10)
But really, please consider just adjusting the CSS to permit the modal to expand naturally rather than involving JavaScript at all.
Place this BEFORE any HTML elements.
<script src="/path/to/jquery.js"></script>
<script>
$(document).ready(function(){
var textarea = $('#history');
alert(textarea.height()); //returns correct height
});
</script>
You obviously do not have to alert it. I was just using an easily visible example.
Given a textarea with an id of "history", this jQuery will return it's height:
$('#history').height()
Please see a working example at http://jsfiddle.net/jhfrench/JcGGR/
You can also retrieve the height in pixels by using $('#history').css('height'); if you're not planning on doing any calculations.
for current height in px:
height = window.getComputedStyle(document.querySelector('textarea')).getPropertyValue('height')
for current width in px:
width = window.getComputedStyle(document.querySelector('textarea')).getPropertyValue('width')
change 'textarea' to '#history' or like a css selector. or textarea, since a variable is declared to select element.

I can't get a Div's width using element.style.width. Do I have to use element.clientWidth instead?

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...

Categories