Get real width of elements with jQuery - javascript

I am writing a validator for "visual correctness" of html files. The goal is to detect too wide elements.
Here is a demo of my problem.
The dotted red line is an indicator of the max width of the document (200px in this example). The first paragraph is fine, but the second is too wide. Nevertheless, all of the following commands still return "200px" as the width:
// all return 200, but the value should be larger
$('#two').width();
$('#two').outerWidth();
$('#two').prop('clientWidth');
Please see the Fiddle for more details.
How can i detect such oversized elements?
Updated question: Better to ask, how can i detect text that exceeds the borders of their parent elements?
Updated requirement: I am not allowed to change anything in the source HTML or CSS. But i can do anything i want with jQuery to modify the document, so that i can detect those too wide elements.

As others have said, temporarily wrap the text node in an inline element.
var two = document.getElementById('two'),
text = two.firstChild,
wrapper = document.createElement('span');
// wrap it up
wrapper.appendChild(text);
two.appendChild(wrapper);
// better than bad, it's good.
console.log(wrapper.offsetWidth);
// put it back the way it was.
two.removeChild(wrapper);
two.appendChild(text);
http://jsfiddle.net/vv68y/12/
Here is a getInnerWidth function that should be useful to you. Pass it an element and it will handle the wrapping and unwrapping.
function getInnerWidth(element) {
var wrapper = document.createElement('span'),
result;
while (element.firstChild) {
wrapper.appendChild(element.firstChild);
}
element.appendChild(wrapper);
result = wrapper.offsetWidth;
element.removeChild(wrapper);
while (wrapper.firstChild) {
element.appendChild(wrapper.firstChild);
}
return result;
}
http://jsfiddle.net/vv68y/13/

scrollWidth will do it:
$("#two").get()[0].scrollWidth
or
getElementById("two").scrollWidth
this outputs 212px, the real width you are looking for.

This effect is called "shrinkwrapping", and there's a couple of ways to determine the "real" width of the element.
Float
One of the ways that you can use is to float your <p> element which will force it as small as possible, but you'll need to use a clearfix if anything inside your div is floating:
#two { float: left; }
Inline-block element
Inserting an inline element should work.
<p>content</p>
would become
<p><span>content</span></p>
Absolutely positioned element
Changing the element position to be absolute should also work:
#two { position: absolute; }
If you can't statically change the markup or the style, you can always change them dynamically through JavaScript.
(absolutely positioned element)
var realWidth = $("#two").css("position", "absolute").width();
(float)
var realWidth = $("#two").css("float", "left").width();
(inline-block element)
var t = $("#two").html();
var realWidth = $("#two")
.empty()
.append($("<span>").html(t))
.width();

Apply word-wrap: break-word; to it.. so the word will break and there won't be any text going out of the container... btw you can't check the width of the text which is going out of the container.
Example
Update: You can check if the width of text in it is bigger than the width of the container like this

As others have pointed out, changing the position of the element to absolute also works.
Doing this will result in an inline-style which can mess with your css afterwards if you don't watch out. Here is a solution to get rid of the inline style again.
//Change position to absolute
$('#two').css("position", "absolute");
var textWidth = $('#two').width();
//Get rid of the inline style again
$('#two').removeStyle("position");
//Plugin format
(function ($) {
$.fn.removeStyle = function (style) {
var search = new RegExp(style + '[^;]+;?', 'g');
return this.each(function () {
$(this).attr('style', function (i, style) {
return style.replace(search, '');
});
});
};
}(jQuery));

The element itself is constrained to 200px, but the text inside spills out. If you insert a span (or any other inline element) inside the P tag it works fine.
http://jsfiddle.net/will/vv68y/5/
Hope that helps :)

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;

Apply style to span based on number of lines within a cycling banner

Context
Here is a jsfiddle that I've been working with: http://jsfiddle.net/21r7uvgx/
For context, I'm using http://malsup.com/jquery/cycle/basic.html to make the rotating banner cycle through each <a> within the .custom-banners wrapper. I have the script as an external resource within the jsfiddle.
Starting Point
The idea is to make each span that has multiple lines (purely from window size) apply Style A, and those that have just one line apply Style B. Resizing the window changes what style each span gets.
I'm doing it to the span instead of the a based on the assumption that to achieve what I want, I need to target a element that displays as a block by default.
Issue and Goal
The issue I'm running into is that with the cycling script, a span that is not visible has a height of 0, so the math isn't right and it won't apply the correct style, even once the span becomes visible.
The goal is to find a way to have it check a span when it becomes visible, and apply the correct style.
Bonus Goal
If there's a better way to calculate the lineheight and determine what style needs to be applied, I'd also like those suggestions.
I was using this before, but it was very buggy when I manually resized the window.
var divheight = $(this).height();
var lineheight = $(this).css('line-height').replace("px","");
if (Math.round(divheight/parseInt(lineheight)) >= 2) {
$(this).attr('style','font-size: 10px');
} else {
$(this).attr('style','font-size: inherit');
};
Try this javascript. I have edited your javascript from the jsfiddle that you linked. If you don't want to change the font color (as in jsfiddle) and just want to change font size, then do it appropriately. Copy paste the below code to your jsfiddle and verify.
$(document).ready(function () {
$(window).on("resize", function () {
$('.custom-banners span').each(function () {
var lineheight = 20;
var divheight = $('.banner-link').height();
if (divheight > lineheight) {
$(this).css('color', 'red');
} else {
$(this).css('color', 'green');
};
});
});
});

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.

How to split html to full-screen height pages?

I need to split some html content to pages, so that each page would have height of the screen and some predefined width. Page split can happen in the middle of paragraph (or probably some other html element), so this situation should be handled somehow.
What I really want to achieve is the effect of reading the book, page by page. I assume there will be a need for some javascript, so I'd prefer to to this with jQuery, but if other framework is required, it's also okay.
I have to admit that I'm quite new to HTML and all, so sorry if my guess is stupid, but currently I'm considering the following approach: measure actual height of the visible area (need to figure out how yet), then take my html document and incrementally take tag after tag, put this into invisible div and calculate its resulting height. When I'll have its height more than page height, I'm done. However, this approach will not work in case of long tags, e.g. long paragraph.
Thanks in advance.
EDIT: thanks for your previous answers. I tried to use approach of manual calculating the size of the elements, and encountered one problem which I cannot solve in a good way. This is problem of collapsing margins. What I'm trying to do is to loop through all the paragraphs in my document and sum up results of .outerHeight(true) jQuery call. This should give me the full height of element, including padding, margin and border. And it actually does what it says, but the problem here is that it doesn't take collapsing margins into account. Because of that I end up with wrong overall size (bigger than real one), because browser throws away some of margins (of adjacent paragraphs in my case), but I take them into account.
Any ideas how to solve this other than introducing the algorithm deciding which margins are collapsed and which are not? I think it is ugly...
You could use CSS3 multi-column rules, example: http://www.quirksmode.org/css/multicolumn.html
Or for support in all browsers use a javascript plugin: http://welcome.totheinter.net/columnizer-jquery-plugin/
This plugin even has a multi-page multi-column example: http://welcome.totheinter.net/2009/06/18/dynamic-multi-page-multi-column-newsletter-layout-with-columnizer/
I can think of one framework which seems to do what you need (and a bit more): https://github.com/Treesaver/treesaver
jQuery will give you the height (in pixels) of an element with the height() function.
jQuery("BODY").height() will give you the maximum height of the view port (though only if your content height is >= the height of the BODY - otherwise it will give you the height of how much space the body is taking up in the view port.)
Counting the heights of the P tags (or other tags) seems like a good way to go. I suppose if you want to break up the content of a P tag for large paragraphs, you could define a maximum "breakage" height for the last P tag on a page. You can then break rest of the contents of the P tag by creating a new P tag with jQuery("#the-next-page-id).append(jQuery("<P>"+restOfTheParagraphContent+"</P>"))
Use your own logic to calculate the height of each element in the html body
using jQuery code
$('selector').height();
Using this, you can calculate the height of some html elements and decide how much
elements should be displayed on your device screen.
for more, please visit jQuery Height Documentation
In case anyone still looking for something like this I recently did it using JQuery. It also leaves the first page empty (for title and such):
https://jsfiddle.net/xs31xzvt/
It basically iterates over the movable items and insert them into a new div if the previous div is full.
(function($) {
$(document).ready(formatPages)
function formatPages() {
var container = $('.container');
var subPage = $('.subpage').get(0);
var subPageHeight = subPage.offsetHeight;
var subPageScrollHeight = subPage.scrollHeight;
// See how many pages we'll need
var pages = Math.floor(subPageScrollHeight / subPageHeight) + 1;
//add a new page
var pageCount = 2;
var pageDiv = createPageDiv(pageCount);
var subPageDiv = createSubPageDiv(pageCount);
var addPage = function (){
pageCount++;
pageDiv = createPageDiv(pageCount);
subPageDiv = createSubPageDiv(pageCount);
pageDiv.append(subPageDiv);
container.append(pageDiv);
pageContentHeight = 0;
}
addPage()
container.append(pageDiv);
$('.movable').each(function() {
var element = $(this);
//remove the element
element.detach();
//try to add the element to the current page
if (pageContentHeight + element.get(0).offsetHeight > subPageHeight) {
subPageDiv.append(getFooterDiv().show());
//add a new page
addPage();
}
subPageDiv.append(element);
pageContentHeight += element.get(0).offsetHeight;
});
}
function createPageDiv(pageNum) {
return $('<div/>', {
class: 'page',
id: 'page' + pageNum
});
}
function createSubPageDiv(pageNum) {
return $('<div/>', {
class: 'subpage',
id: 'subpage' + pageNum
});
}
function getFooterDiv() {
return $('.footer').first().clone();
}
}(jQuery));

jQuery: Get height of hidden element in jQuery

I need to get height of an element that is within a div that is hidden. Right now I show the div, get the height, and hide the parent div. This seems a bit silly. Is there a better way?
I'm using jQuery 1.4.2:
$select.show();
optionHeight = $firstOption.height(); //we can only get height if its visible
$select.hide();
You could do something like this, a bit hacky though, forget position if it's already absolute:
var previousCss = $("#myDiv").attr("style");
$("#myDiv").css({
position: 'absolute', // Optional if #myDiv is already absolute
visibility: 'hidden',
display: 'block'
});
optionHeight = $("#myDiv").height();
$("#myDiv").attr("style", previousCss ? previousCss : "");
I ran into the same problem with getting hidden element width, so I wrote this plugin call jQuery Actual to fix it. Instead of using
$('#some-element').height();
use
$('#some-element').actual('height');
will give you the right value for hidden element or element has a hidden parent.
Full documentation please see here. There is also a demo include in the page.
Hope this help :)
You are confuising two CSS styles, the display style and the visibility style.
If the element is hidden by setting the visibility css style, then you should be able to get the height regardless of whether or not the element is visible or not as the element still takes space on the page.
If the element is hidden by changing the display css style to "none", then the element doesn't take space on the page, and you will have to give it a display style which will cause the element to render in some space, at which point, you can get the height.
I've actually resorted to a bit of trickery to deal with this at times. I developed a jQuery scrollbar widget where I encountered the problem that I don't know ahead of time if the scrollable content is a part of a hidden piece of markup or not. Here's what I did:
// try to grab the height of the elem
if (this.element.height() > 0) {
var scroller_height = this.element.height();
var scroller_width = this.element.width();
// if height is zero, then we're dealing with a hidden element
} else {
var copied_elem = this.element.clone()
.attr("id", false)
.css({visibility:"hidden", display:"block",
position:"absolute"});
$("body").append(copied_elem);
var scroller_height = copied_elem.height();
var scroller_width = copied_elem.width();
copied_elem.remove();
}
This works for the most part, but there's an obvious problem that can potentially come up. If the content you are cloning is styled with CSS that includes references to parent markup in their rules, the cloned content will not contain the appropriate styling, and will likely have slightly different measurements. To get around this, you can make sure that the markup you are cloning has CSS rules applied to it that do not include references to parent markup.
Also, this didn't come up for me with my scroller widget, but to get the appropriate height of the cloned element, you'll need to set the width to the same width of the parent element. In my case, a CSS width was always applied to the actual element, so I didn't have to worry about this, however, if the element doesn't have a width applied to it, you may need to do some kind of recursive traversal of the element's DOM ancestry to find the appropriate parent element's width.
Building further on user Nick's answer and user hitautodestruct's plugin on JSBin, I've created a similar jQuery plugin which retrieves both width and height and returns an object containing these values.
It can be found here:
http://jsbin.com/ikogez/3/
Update
I've completely redesigned this tiny little plugin as it turned out that the previous version (mentioned above) wasn't really usable in real life environments where a lot of DOM manipulation was happening.
This is working perfectly:
/**
* getSize plugin
* This plugin can be used to get the width and height from hidden elements in the DOM.
* It can be used on a jQuery element and will retun an object containing the width
* and height of that element.
*
* Discussed at StackOverflow:
* http://stackoverflow.com/a/8839261/1146033
*
* #author Robin van Baalen <robin#neverwoods.com>
* #version 1.1
*
* CHANGELOG
* 1.0 - Initial release
* 1.1 - Completely revamped internal logic to be compatible with javascript-intense environments
*
* #return {object} The returned object is a native javascript object
* (not jQuery, and therefore not chainable!!) that
* contains the width and height of the given element.
*/
$.fn.getSize = function() {
var $wrap = $("<div />").appendTo($("body"));
$wrap.css({
"position": "absolute !important",
"visibility": "hidden !important",
"display": "block !important"
});
$clone = $(this).clone().appendTo($wrap);
sizes = {
"width": $clone.width(),
"height": $clone.height()
};
$wrap.remove();
return sizes;
};
Building further on Nick's answer:
$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'});
optionHeight = $("#myDiv").height();
$("#myDiv").css({'position':'static','visibility':'visible', 'display':'none'});
I found it's better to do this:
$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'});
optionHeight = $("#myDiv").height();
$("#myDiv").removeAttr('style');
Setting CSS attributes will insert them inline, which will overwrite any other attributes you have in your CSS file. By removing the style attribute on the HTML element, everything is back to normal and still hidden, since it was hidden in the first place.
You could also position the hidden div off the screen with a negative margin rather than using display:none, much like a the text indent image replacement technique.
eg.
position:absolute;
left: -2000px;
top: 0;
This way the height() is still available.
I try to find working function for hidden element but I realize that CSS is much complex than everyone think. There are a lot of new layout techniques in CSS3 that might not work for all previous answers like flexible box, grid, column or even element inside complex parent element.
flexibox example
I think the only sustainable & simple solution is real-time rendering. At that time, browser should give you that correct element size.
Sadly, JavaScript does not provide any direct event to notify when element is showed or hidden. However, I create some function based on DOM Attribute Modified API that will execute callback function when visibility of element is changed.
$('[selector]').onVisibleChanged(function(e, isVisible)
{
var realWidth = $('[selector]').width();
var realHeight = $('[selector]').height();
// render or adjust something
});
For more information, Please visit at my project GitHub.
https://github.com/Soul-Master/visible.event.js
demo: http://jsbin.com/ETiGIre/7
Following Nick Craver's solution, setting the element's visibility allows it to get accurate dimensions. I've used this solution very very often. However, having to reset the styles manually, I've come to find this cumbersome, given that modifying the element's initial positioning/display in my css through development, I often forget to update the related javascript code. The following code doesn't reset the styles per say, but removes the inline styles added by javascript:
$("#myDiv")
.css({
position: 'absolute',
visibility: 'hidden',
display: 'block'
});
optionHeight = $("#myDiv").height();
optionWidth = $("#myDiv").width();
$("#myDiv").attr('style', '');
The only assumption here is that there can't be other inline styles or else they will be removed aswell. The benefit here, however, is that the element's styles are returned to what they were in the css stylesheet. As a consequence, you can write this up as a function where an element is passed through, and a height or width is returned.
Another issue I've found of setting the styles inline via js is that when dealing with transitions through css3, you become forced to adapt your style rules' weights to be stronger than an inline style, which can be frustrating sometimes.
By definition, an element only has height if it's visible.
Just curious: why do you need the height of a hidden element?
One alternative is to effectively hide an element by putting it behind (using z-index) an overlay of some kind).
In my circumstance I also had a hidden element stopping me from getting the height value, but it wasn't the element itself but rather one of it's parents... so I just put in a check for one of my plugins to see if it's hidden, else find the closest hidden element. Here's an example:
var $content = $('.content'),
contentHeight = $content.height(),
contentWidth = $content.width(),
$closestHidden,
styleAttrValue,
limit = 20; //failsafe
if (!contentHeight) {
$closestHidden = $content;
//if the main element itself isn't hidden then roll through the parents
if ($closestHidden.css('display') !== 'none') {
while ($closestHidden.css('display') !== 'none' && $closestHidden.size() && limit) {
$closestHidden = $closestHidden.parent().closest(':hidden');
limit--;
}
}
styleAttrValue = $closestHidden.attr('style');
$closestHidden.css({
position: 'absolute',
visibility: 'hidden',
display: 'block'
});
contentHeight = $content.height();
contentWidth = $content.width();
if (styleAttrValue) {
$closestHidden.attr('style',styleAttrValue);
} else {
$closestHidden.removeAttr('style');
}
}
In fact, this is an amalgamation of Nick, Gregory and Eyelidlessness's responses to give you the use of Gregory's improved method, but utilises both methods in case there is supposed to be something in the style attribute that you want to put back, and looks for a parent element.
My only gripe with my solution is that the loop through the parents isn't entirely efficient.
One workaround is to create a parent div outside the element you want to get the height of, apply a height of '0' and hide any overflow. Next, take the height of the child element and remove the overflow property of the parent.
var height = $("#child").height();
// Do something here
$("#parent").append(height).removeClass("overflow-y-hidden");
.overflow-y-hidden {
height: 0px;
overflow-y: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent" class="overflow-y-hidden">
<div id="child">
This is some content I would like to get the height of!
</div>
</div>
Here's a script I wrote to handle all of jQuery's dimension methods for hidden elements, even descendants of hidden parents. Note that, of course, there's a performance hit using this.
// Correctly calculate dimensions of hidden elements
(function($) {
var originals = {},
keys = [
'width',
'height',
'innerWidth',
'innerHeight',
'outerWidth',
'outerHeight',
'offset',
'scrollTop',
'scrollLeft'
],
isVisible = function(el) {
el = $(el);
el.data('hidden', []);
var visible = true,
parents = el.parents(),
hiddenData = el.data('hidden');
if(!el.is(':visible')) {
visible = false;
hiddenData[hiddenData.length] = el;
}
parents.each(function(i, parent) {
parent = $(parent);
if(!parent.is(':visible')) {
visible = false;
hiddenData[hiddenData.length] = parent;
}
});
return visible;
};
$.each(keys, function(i, dimension) {
originals[dimension] = $.fn[dimension];
$.fn[dimension] = function(size) {
var el = $(this[0]);
if(
(
size !== undefined &&
!(
(dimension == 'outerHeight' ||
dimension == 'outerWidth') &&
(size === true || size === false)
)
) ||
isVisible(el)
) {
return originals[dimension].call(this, size);
}
var hiddenData = el.data('hidden'),
topHidden = hiddenData[hiddenData.length - 1],
topHiddenClone = topHidden.clone(true),
topHiddenDescendants = topHidden.find('*').andSelf(),
topHiddenCloneDescendants = topHiddenClone.find('*').andSelf(),
elIndex = topHiddenDescendants.index(el[0]),
clone = topHiddenCloneDescendants[elIndex],
ret;
$.each(hiddenData, function(i, hidden) {
var index = topHiddenDescendants.index(hidden);
$(topHiddenCloneDescendants[index]).show();
});
topHidden.before(topHiddenClone);
if(dimension == 'outerHeight' || dimension == 'outerWidth') {
ret = $(clone)[dimension](size ? true : false);
} else {
ret = $(clone)[dimension]();
}
topHiddenClone.remove();
return ret;
};
});
})(jQuery);
If you've already displayed the element on the page previously, you can simply take the height directly from the DOM element (reachable in jQuery with .get(0)), since it is set even when the element is hidden:
$('.hidden-element').get(0).height;
same for the width:
$('.hidden-element').get(0).width;
(thanks to Skeets O'Reilly for correction)

Categories