Optimize this JS function to avoid Forced reflow - javascript

there is a code snippet. DevTools marks 4 tasks (Recalculate style + Layout) as Long tasks with Forced reflows. They refer to this code snippet:
e(function() {
var t = document.body
, i = t.appendChild(i = document.createElement("div"));
i.offsetHeight,
e.extend(i.style, {
minHeight: "100px",
height: "auto",
padding: 0,
borderWidth: 0
}),
e.support.minHeight = 100 === i.offsetHeight,
e.support.selectstart = "onselectstart"in i,
t.removeChild(i).style.display = "none"
}),
I have 2 questions:
what does this code actually do?
how to optimize it to not have the reflows?
Here is what I have regarding the 1st question:
The given JavaScript function is creating a new div element and appending it to the body of the HTML document. Then, it is setting various styles for the newly created div element and testing if the styles are supported by the browser. Specifically, it sets the minimum height of the div element to 100px, sets the height to "auto", sets padding and border width to 0, and tests if the minimum height of 100px is supported by checking the offsetHeight property of the div element. In short, there are manipulations with the DOM, which cause the Forced reflows.
The forced reflow is happening because of the style changes made to the newly created element "i". Whenever the styles of an element are updated, the browser recalculates the layout of the entire page and then repaints it, which is known as a forced reflow. In this case, when the "minHeight" property is set to "100px", the browser has to recalculate the layout, as the height of the element has changed. Then, when the "height" property is set to "auto", the layout is recalculated again, which is why a forced reflow is triggered.
It is generally considered best practice to minimize forced reflows, as they can significantly impact the performance of your website or web application. One way to minimize forced reflows is to batch style updates, so that multiple changes can be made to the elements in a single layout recalculation and repaint.
What I have regarding the 2nd question:
To optimize the code and minimize forced reflows, you could batch the style updates into a single update by modifying the style properties before appending the element to the body. Here's an example:
e(function() {
var i = document.createElement("div");
e.extend(i.style, {
minHeight: "100px",
height: "auto",
padding: 0,
borderWidth: 0,
display: "none"
});
var t = document.body.appendChild(i);
i.offsetHeight;
e.support.minHeight = 100 === i.offsetHeight;
e.support.selectstart = "onselectstart" in i;
});
By making all of the style updates before the element is added to the body, you can minimize the number of forced reflows that occur. The layout of the page will only be recalculated once, when the element is added, rather than after each individual style update.
Are the answers correct? I am bad at JS and I doubt. Thank you.

Related

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

Raphael.js causing "Forced synchronous layout" bottleneck

I monitored the page load time for my site in chrome (using Timeline), and got hundreds of warnings that said "Forced synchronous layout is a possible performance bottleneck" for all the Raphael.js calls:
I don't know how to fix this :/
Any ideas on where to look?
Here's how I normally create text on the page:
currentPaper.text(width,height,"text")
.attr({opacity:.8, fill: "#333", 'font-size':10})
.id = "someId";
//Or, to be exact:
currentPaper.text(x_pos+(width/2),
y_pos-height/8,
lopaLayoutArray.x[s].y1[r].y2[x])
.attr({opacity:.8, fill: "#333", 'font-size':(10*size)})
.id = seatName+"-textLabel";
Thanks!
Problem:
The problem is called "Layout Thrashing" and is happening because the browser was trying to immediately refresh / redraw after every Raphael drawing.
For example, this would cause layout thrashing:
var a = document.getElementById('element-a');
var b = document.getElementById('element-b');
a.clientWidth = 100;
var aWidth = a.clientWidth;
b.clientWidth = 200;
var bWidth = b.clientWidth;
"In this simple example, the browser will update the whole layout twice. This is because after setting the first element's width, you are asking to retrieve an element's width. When retrieving the css property, the browser know's it needs updated data, so it then goes and updates the whole DOM tree in memory. Only then, it will continue to the next line, which will soon after cause another update because of the same reasons."
This can simply be fixed by changing around the order of the code, as so :
var a = document.getElementById('element-a');
var b = document.getElementById('element-b');
a.clientWidth = 100;
b.clientWidth = 200;
var aWidth = a.clientWidth;
var bWidth = b.clientWidth;
"Now, the browser will update both properties one after the other without updating the tree."
Sources:
https://blog.idrsolutions.com/2014/08/beware-javascript-layout-thrashing/
http://www.codeproject.com/Articles/758790/Debugging-and-solving-the-Forced-Synchronous-Layou
http://www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-your-javascript-slow/
https://dev.opera.com/articles/efficient-javascript/?page=3#reflow
Soultion:
One way to fix this (a really quick and dirty way) is to hide() the div you are drawing to, then, when you are finished, show() it. I have had hit and miss results with this with Raphael, and it has been drawing strange this way. However it is faster...
"When an element has its display style set to none, it will not need to repaint, even if its contents are changed, since it is not being displayed. This can be used as an advantage. If several changes need to be made to an element or its contents, and it is not possible to combine these changes into a single repaint, the element can be set to display:none, the changes can be made, then the element can be set back to its normal display."
Here's the results:
This way worked for me!

How can I trigger CSS layout recalculation after Javascript DOM updates?

I often find that if I create or reparent DOM nodes in javascript, the CSS engine doesn't recalculate the sizes of the parent containers. This happens in Firefox and Chrome.
For example, the body might stay the same size while new content overflows the bottom. If I resize the window the body grows, but it doesn't "lock in" to its correct size until the window is sized to be at least as big as the body should be.
Is there a way to trigger a full layout recomputation in Javascript?
I can able to trigger CSS Engine via:
document.body.style.zoom = 1.0000001;
setTimeout(function(){document.body.style.zoom = 1;},50); //allow some time to flush the css buffer.
For every time after resizing the window use the following:
$(window).resize(function() {
if(this.resizeTO) clearTimeout(this.resizeTO);
this.resizeTO = setTimeout(function() {
$(this).trigger('resizeEnd');
}, 500);
});
$(window).bind('resizeEnd', function() {
document.body.style.zoom = 1.0000001;
setTimeout(function(){document.body.style.zoom = 1;},50);
});
You can trigger a repaint from JavaScript by setting a CSS style to an innocuous value, e.g.
document.body.style.zIndex = 1;
Yes. I tend to put a random className on the <html> element, using:
document.documentElement.className = 'reflow_' + (new Date()).getTime();
which creates:
<html class="reflow_1483757400611">
Tried and tested on everything from Android Browser 4 to Smart TV's via camposat.tv
The browser does recompute the geometry of all elements after DOM manipulation. One likely reason you might see an element "stuck" at a certain height even after its content has changed is this CSS rule:
body { height: 100% };
It tells the browser, make the body element as large in height as the viewport regardless of its content.
Try changing it to:
body { min-height: 100% };
This will tell the browser to make body at least as large in height as the viewport or larger if there is more content.

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.

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