4

I am trying to set the height of absolutely positioned items to match the height of their container element. The problem is that there are hundreds of these elements. The standard code in the title runs great in chrome, but drags like crazy in IE. How should i mitigate this issue?

    //Too SLOW in IE
    var starttime = new Date().getTime();
    $("#grdSchedule > tbody > tr").each(function(i) {
        thisRow = $(this);
        thisRow.children(".stickyCol").height(thisRow.height());
        //thisRow.children().slice(0, 1).css('height', thisRow.css('height'));            
    });
        var taskTime = (new Date().getTime() - starttime) / 1000;
        alert("cell height stretch: " + taskTime); 

It seems as if just setting the height doesnt sloe it doen that much, but setting the height from a .height() of something else really causes IE to choke.

I have tries .css() instead with a little boost but not much.

Here is a fiddle to fiddle with: Fiddle AWAY!!!

jumpdart
  • 1,702
  • 16
  • 35
  • 1
    .css() should definitely be much faster, however you can probably make this whole process a LOT faster by detaching the table before you loop through it, then reattaching it when you're done. http://jsfiddle.net/hnZxn/2/ – Kevin B Jan 18 '13 at 16:20
  • You can also improve performance by storing `thisRow.height()` in a variable. – Rory McCrossan Jan 18 '13 at 16:20
  • Are the row heights highly dynamic? Your script depends on finding out the *computed* height values, it should be way faster if you could leave that out (by using a fixed height, or a precalculated one). – bfavaretto Jan 18 '13 at 16:23
  • Detaching the element has halved the time taken in FF (from ~0.1s to ~0.04s) http://jsfiddle.net/RoryMcCrossan/hnZxn/3/ – Rory McCrossan Jan 18 '13 at 16:27
  • @bfavaretto- unfortunately the table cells are filled with dynamic content that would make it difficult to precalculate their hight – jumpdart Jan 18 '13 at 16:28
  • 1
    @KevinB - Detaching the table from the DOM will most likely mess with the styling. – Joseph Silber Jan 18 '13 at 16:32

4 Answers4

3

With IE9, I went from 1.6 seconds to 0.031 seconds. With Chrome, I went from 0.302 seconds to 0.018 seconds.

Working example with detach() (fastest, but will cause layout problems if you delayed the re-insertion of the table--that is, if you allow the page to re-render without the table in the DOM).

Working example with a plain DocumentFragment clone

The key is to clone the table as a DocumentFragment (or temporarily remove it from the DOM with detach() and manipulate the cell heights of the cloned table (i.e., before the table is part of the DOM). Then after all the height calculations have been made, replace the original table with the cloned table.

The .height() calculations weren't slowing you down, it's the fact you were traversing and manipulating the DOM in a big loop. Of the big three browsers, Internet Explorer is the slowest at DOM manipulation.

For some further reading, a while back I put together some DOM insertion benchmarks that give a good measure of relative browser performance with the DOM. John Resig has also written on the use the DocumentFragments and DOM manipulation: http://ejohn.org/blog/dom-documentfragments/

Elliot B.
  • 17,060
  • 10
  • 80
  • 101
  • i like the clone stuff and detaching is definitely a plus, but getting all the sizes first really helps too. – jumpdart Jan 18 '13 at 18:25
  • If you're performing DOM traversal to get the sizes beforehand, then that will slow you down as well. For best performance, you want to keep DOM traversal and manipulation to a minimum. – Elliot B. Jan 18 '13 at 18:28
  • Try it! http://jsfiddle.net/jumpdart/hnZxn/13/! sorry im having fiddle issues... takes even less time to have the sizes first – jumpdart Jan 18 '13 at 18:39
  • I originally posted this question on a different SE site and it got transfered here. Before that question got deleted as a duplicate someone answered with getting the sizes separately efore you loop though to set them and it definitely speeds things up. I just wish they would have moved that answer to this question before it got axed. – jumpdart Jan 18 '13 at 18:55
  • did you try adding the precalcs to itto see if it speeded up or slowed down? Mine is still a little faster than yours on my pc. I kinda want to mark yours as the anser for the explanation and the links and whatnot, but mine still is a bit faster – jumpdart Jan 18 '13 at 19:07
  • it actually looks like if you ONLY do the precalcs, it is the fastest, and dont even worry about detaching it... working on fiddle now http://jsfiddle.net/jumpdart/MrQVv/ – jumpdart Jan 18 '13 at 19:32
  • 1
    Your Fiddle example doesn't include the time it takes to traverse through the DOM to perform the pre-calculation. Move the `new Date()` to the top of the function and you'll see that it takes longer: http://jsfiddle.net/MrQVv/1/ – Elliot B. Jan 18 '13 at 20:54
  • oops yeah it takes a little longer... but is still quicker than yours – jumpdart Jan 18 '13 at 21:12
  • sorry for bugging you all day about this... i have a monster table that im tryin to squeeze every ounce of performance out of – jumpdart Jan 18 '13 at 21:19
  • in these fiddles the hight for the row is defined in the css. If the hight is not explicitly defined, it will be 0 when not in the dom. In that case, what would be the best way to determine the row heights? – jumpdart Mar 05 '13 at 15:47
0

Avoid creating a separate object for the row, and cache the row's height:

 $('#grdSchedule > tbody > tr').each(function () {
    var height = $.css(this, height);
    $('.stickyCol', this).css('height', height );           
});
Joseph Silber
  • 214,931
  • 59
  • 362
  • 292
0

Looks like the precalcs on their own is enough to really speed things up, and comes with the benefit of not worrying about any complications from detaching

    var starttime = new Date().getTime();
    var stickyCols = 1;
    //get row heights
    var rowHeights = new Array();
    $("#grdSchedule > tbody > tr").each(function(i) {
        rowHeights[i] = $(this).css('height');
    });

    //Now SUPERDUPERFAST in IE
    //var $table = $("#grdSchedule").detach();            
    $("#grdSchedule > tbody > tr").each(function(i) {
    //$(" > tbody > tr", $table).each(function(i) {
        thisRow = $(this);
        thisRow.children("td").slice(0, stickyCols).css('height', rowHeights[i]);              
    });
    //$("#scrollDiv_top").append($table);
    var taskTime = (new Date().getTime() - starttime) / 1000;
    alert("cell height stretch: " + taskTime); 

FIDDLE

jumpdart
  • 1,702
  • 16
  • 35
  • 1
    You need to move `var starttime = new Date().getTime();` to the top of the function. If the pre-calc is part of the solution, then it should be added to the total time. When you do that, it's a little bit slower. – Elliot B. Jan 18 '13 at 20:55
  • . ok so maybe not SUPERDUPER FAST but its still the fastest one posted – jumpdart Jan 18 '13 at 21:13
  • On my browser it's slower than my example by half a hundredth of a second ;) – Elliot B. Jan 18 '13 at 21:14
  • well add it as an option on your answer so i can give you a green check – jumpdart Jan 18 '13 at 21:16
  • WARNING: come to find out that this precalc stuff is super slow in older browsers. just use the detatch! – jumpdart Mar 04 '13 at 22:29
0

What's wrong with just setting height:100% on the absolutely-positioned element?

Updated Fiddle

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592