7

Is there an elegant way to predict the dimension an element will have after the elements transition is complete?

Example:

HTML:

<div id="demo">...</div>

CSS:

#demo {
  max-height: 0;
  overflow:hidden;
  transition: 2s max-height;
}

#demo.expand {
  max-height: 1000px;
}

JS:

 var demo = document.getElementById('demo');
 demo.className = 'expand';
 // Unfortunately the result will be 0px 
 // because the current height is measured
 alert(demo.offsetHeight);

Demo:

codepen

jantimon
  • 36,840
  • 23
  • 122
  • 185
  • It's not entirely clear to me what you are trying to do. Why `max-height`? – Paulie_D Apr 30 '14 at 16:07
  • Yeah, I get that it's a workaround but what are you actually trying to do? So, I guess I'm asking **"Why do you need the height?"** – Paulie_D Apr 30 '14 at 16:11
  • I wonder if this is a job for element.getBoundingClientRect(). Can you make a fiddle where we might test it? – TimSPQR Apr 30 '14 at 17:22
  • 1
    I think I understand your question now. I'm guessing you don't want to "measure the dimension", but you want to "predict the dimensions" of the element prior to it's placement on the screen. Is that correct? – TimSPQR May 01 '14 at 01:05
  • Ok, so this is going to be a bit more difficult - You'd have to know the characteristics of the div, do some calculations, and hope that the div won't change size when in position. Last night I was thinking about opening the div for a very short period of time (in position, or a different, distant part of the page), making the measurements, and then moving into the right position after hiding it. Maybe if you tell us why you need the measurements before you load it, we might be able to come up with a different strategy. – TimSPQR May 01 '14 at 20:42
  • I guess I will have to add an additional css class: http://stackoverflow.com/questions/11131875/what-is-the-cleanest-way-to-disable-css-transition-effects-temporarily – jantimon May 01 '14 at 21:34

6 Answers6

4

Is there an elegant way to measure the dimension an element will have after the elements transition is complete?

You can use the transitionend event to look at the height of your element after the transition is finished:

$('#demo').on("transitionend", function(e) { 
    console.log($('#demo').height());
}).addClass('expand');

This will get you a value of 20, which I assume is what you are looking for?
jsFiddle

joker
  • 982
  • 9
  • 23
CBroe
  • 91,630
  • 14
  • 92
  • 150
  • Unfortunately I need the information before the animation is completed. – jantimon Apr 30 '14 at 21:53
  • 1
    Well then you will have to get that _before_ limiting the height of the element in the first place – i.e., remove `max-height` and `overflow`, and check the element dimensions. Do it off-screen (f.e. using absolute positioning) if you can’t have the elements content show up while doing so. – CBroe Apr 30 '14 at 21:55
2

BlakeGru's answer works great for the OP's question, but doesn't work for similar problems that I've encountered. For completeness, and in case it's useful for others, here is a general strategy for finding the final dimensions an element will have once any transitions have been completed, before said transitions actually begin.

This example changes the width of an element (with a transition) and gets the height (which is determined automatically by content) that the element will have once the transition has finished.

function resize(element, endingWidth) {
  // First, save any set transitions for later.
  var transitions = window.getComputedStyle(element).transition;
  // Now, disable any transitions so that our calculations will work properly.
  element.style.transition = 'none';
  // Get our current width.
  var startingWidth = element.offsetWidth + 'px';

  // Set a new width.
  element.style.width = endingWidth;
  // And get the element height. Because there are no transitions set, this will be the same height as at the end of any transitions.
  var endingHeight = element.offsetHeight;

  /*
   * Now do whatever calculations we want with the ending height.
   */
  alert(endingHeight);

  // Set the element's width back to when we started, so we have a start point for our transition.
  element.style.width = startingWidth;
  // Force the browser to recalculate the element's dimensions. This seemingly pointless call is absolutely critical for the transition to work.
  element.offsetWidth;

  // Now, we can set our desired transitions and the ending width again, and we're away.
  element.style.transition = transitions;
  element.style.width = endingWidth;
}

Fiddle

The general idea is:

  • Remove any transitions.
  • Make the desired changes to the element's dimensions.
  • Measure whatever final dimensions are required.
  • Reset the element's dimensions to the initial values.
  • Reinstate the transitions.
  • Make the desired changes again.
leeman
  • 462
  • 3
  • 9
  • Your solution is very very slow because you are triggering multiple render reflows. – jantimon Jul 02 '18 at 11:42
  • Can't really argue; this solution is definitely wasteful. Although I will say I don't see an obvious performance impact on-screen in my tests. – leeman Jul 02 '18 at 19:11
  • thank you for the forced reflow before restoring transitions! – Aprillion Jun 15 '20 at 12:32
  • Is the element1.offsetWidth reflow (I'm using scrollHeight in my current scenario) a browser bug, or a part of some necessary standard? – John Ernest May 10 '23 at 08:15
1

You can check the requested rendering height/width of content through the scrollHeight and scrollWidth properties.

e.g. try adding alert(demo.scrollHeight); to the JS pane.

BlakeGru
  • 702
  • 5
  • 14
  • 1
    I can't find any information that says that `scrollHeight` returns a `transition`-invariant value. The MDN article on `scrollHeight` doesn't mention transitions at all. – Dai May 25 '20 at 23:47
  • https://jsfiddle.net/xs7qpjk0/ this solution does not work or am I missing something? – sjahan Mar 01 '22 at 08:36
0

If I were trying to do something like this I would just get the height of the containing element. If that be the window, get that. This should get you the number your looking for prior to animation every time.

mcphersonjr
  • 733
  • 12
  • 35
0

You can put #demo in a wrapper with height: 0, which will allow the auto height to calculate, then transition the wrapper to match the height of #demo, then on transition end, change the wrapper height to auto so it will flow just like normal.

Here is a JSFiddle to demonstrate.

(Credit to @CBroe for the on("transitionend", function) which I didn't know about)

HTML

<div id="demoWrapper">
    <div id="demo">
        // content
    </div>
</div>

CSS

#demoWrapper {
    height: 0;
    overflow:hidden;
    background:red;
    transition: 2s height;
}

#demo {
    max-height: 1000px;
}

JavaScript

alert("Calculated height of #demo before transition: " + $('#demo').height());

$('#demoWrapper').height($('#demo').height()).on("transitionend", function(e) {
    $('#demoWrapper').css('height', 'auto');
});
Trevin Avery
  • 2,751
  • 2
  • 20
  • 31
  • 1
    transitionend is to late - i need the correct height before the animation starts – jantimon May 03 '14 at 08:10
  • @Jantimon If you view the demo you will see that it tells you the height of `#demo` **before** the transition. I used `transitionend` to change the height of `#demoWrapper` back to `auto` so it would react to window resizing the same way `#demo` would without the wrapper. – Trevin Avery May 03 '14 at 14:31
  • now I get it - the trick is really cool but it would require me to change the markup and css only to get the height – jantimon May 03 '14 at 17:51
  • If you can't change the markup in the HTML, you could do it in the JavaScript. Just move the content to a new `div` and place it in the parent. [Here is a new fiddle.](http://jsfiddle.net/5C3j6/2/) – Trevin Avery May 03 '14 at 21:08
0

content has an height too and if it is wrap into a tag, you can easily retrieve it .

Here text wrapped in a <p>, wich seems fair to me: DEMO.

G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129