Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animation waits before performing

I'm trying to animate an elements height using css. The way I'm doing it is, I added a touch event to an element. The function adds a className to the element that's supposed to hide, i.e. get a height of 0.

The problem is, when the element gets clicked, the div that's supposed get a height of 0 pauses a second then gets the desired height. It seems like the longer the animation duration is, the long it waits before it animates.

Here's the relevant code:

transition: max-height 2s ease-in-out;

JSFiddle

var heading = document.getElementById('heading'),
  body = document.getElementById('body');

heading.addEventListener('click', hide);
body.addEventListener('transitionend', hideCallback);

function hide() {
  body.className = 'hide';
}

function hideCallback(e) {
  console.log(e.propertyName);
}
#wrapper {
  margin: auto;
  background-color: blue;
  width: 470px;
  text-align: center;
  overflow: hidden;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.17);
  max-height: 400px;
  max-width: 600px;
  padding: 0;
}
#buttonContainer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  align-content: center;
  flex-direction: column;
  margin: auto;
  width: 100px;
  height: 100px;
  color: white;
}
#buttonIcon {
  width: 36px;
  height: 36px;
  line-height: 36px;
  font-size: 35px;
  font-weight: bold;
  display: inline-block;
}
#buttonLabel {
  font-size: 20px;
}
#content {
  width: 100%;
  height: 100%;
  text-align: left;
  transform: translateY(0px);
}
#heading {
  color: white;
  text-align: right;
  margin: 10px;
  font-size: 17px;
}
#body {
  color: #000;
  color: rgba(0, 0, 0, 0.87);
  background-color: #FFF;
  width: 100%;
  max-height: 500px;
  padding: 10px 0;
  box-sizing: border-box;
}
#body.hide {
  transition: max-height 2s ease-in-out;
  max-height: 0;
}
#innerBody {
  height: 200px;
  background-color: orange;
}
<div id="wrapper">
  <div id="buttonContainer"><span id="buttonIcon">My</span><span id="buttonLabel">self</span>
  </div>
  <div id="content">
    <div id="heading">Press Me</div>
    <div id="body">
      <div id="innerBody"></div>
    </div>
  </div>
</div>
like image 395
Jessica Avatar asked Apr 18 '16 22:04

Jessica


People also ask

What is animation delay?

The animation-delay CSS property specifies the amount of time to wait from applying the animation to an element before beginning to perform the animation. The animation can start later, immediately from its beginning, or immediately and partway through the animation.

Does animation affect performance?

Animation can help make a site feel faster and responsive, but animations can also make a site feel slower and janky if not done correctly. Responsive user interfaces have a frame rate of 60 frames per second (fps).

What is animation timing function ease out?

Animations with the ease-in timing function start slow and speed up towards the end. ease-out is the opposite, with a fast start and slow end. ease-in-out animations start slow, speed up in the middle, and end slow.

Which of the following property is used to define a delay before an animation starts?

The animation-delay property specifies a delay for the start of an animation.


2 Answers

You're animating max-height and not height. Animating max-height is a trick that's used for animating the height of elements with an unknown height. You state a very large max-height, and as long as the unknown height is less than the max-height, it works. The only downside is that since your animating something that is bigger than your actual height, it will have a delay. In this case your max-height is 500px, and the height (including padding) is only 220px, which means that more than have the time (~1.1sec) is just reducing the max-height to 220px, and when it gets there, the visual starts to animate.

If, like this example, you know the actual height of the element (220 = padding 10 + innerBody height 200), you can animate the exact height.

If you don't know the height beforehand, try to lower max-height estimates and use an easing that starts fast, like ease-out or use javascript to set the start and end height.

Known height: 220px (watch in full screen):

var heading = document.getElementById('heading'),
  body = document.getElementById('body');

heading.addEventListener('click', hide);
body.addEventListener('transitionend', hideCallback);

function hide() {
  body.className = 'hide';
}

function hideCallback(e) {
  console.log(e.propertyName);
}
#wrapper {
  margin: auto;
  background-color: blue;
  width: 470px;
  text-align: center;
  overflow: hidden;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.17);
  max-height: 400px;
  max-width: 600px;
  padding: 0;
}
#buttonContainer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  align-content: center;
  flex-direction: column;
  margin: auto;
  width: 100px;
  height: 100px;
  color: white;
}
#buttonIcon {
  width: 36px;
  height: 36px;
  line-height: 36px;
  font-size: 35px;
  font-weight: bold;
  display: inline-block;
}
#buttonLabel {
  font-size: 20px;
}
#content {
  width: 100%;
  height: 100%;
  text-align: left;
  transform: translateY(0px);
}
#heading {
  color: white;
  text-align: right;
  margin: 10px;
  font-size: 17px;
}
#body {
  color: #000;
  color: rgba(0, 0, 0, 0.87);
  background-color: #FFF;
  width: 100%;
  height: 220px;
  padding: 10px 0;
  box-sizing: border-box;
}
#body.hide {
  transition: height 2s ease-in-out;
  height: 0;
}
#innerBody {
  height: 200px;
  background-color: orange;
}
<div id="wrapper">
  <div id="buttonContainer"><span id="buttonIcon">My</span><span id="buttonLabel">self</span>
  </div>
  <div id="content">
    <div id="heading">Press Me</div>
    <div id="body">
      <div id="innerBody"></div>
    </div>
  </div>
</div>

Unknown height with javascript - set the actual height before the start of the animation, wait for next frame, and change it to 0 (watch in full screen):

var heading = document.getElementById('heading'),
  body = document.getElementById('body');

heading.addEventListener('click', hide);
body.addEventListener('transitionend', hideCallback);

function hide() {
  body.style.height = body.scrollHeight + 'px'; /** sample actual height, and set it on element **/
  requestAnimationFrame(function() { // wait for next frame
    body.style.height = 0; // change height to 0
  });
}

function hideCallback(e) {
  console.log(e.propertyName);
}
#wrapper {
  margin: auto;
  background-color: blue;
  width: 470px;
  text-align: center;
  overflow: hidden;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.17);
  max-height: 400px;
  max-width: 600px;
  padding: 0;
}
#buttonContainer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  align-content: center;
  flex-direction: column;
  margin: auto;
  width: 100px;
  height: 100px;
  color: white;
}
#buttonIcon {
  width: 36px;
  height: 36px;
  line-height: 36px;
  font-size: 35px;
  font-weight: bold;
  display: inline-block;
}
#buttonLabel {
  font-size: 20px;
}
#content {
  width: 100%;
  height: 100%;
  text-align: left;
  transform: translateY(0px);
}
#heading {
  color: white;
  text-align: right;
  margin: 10px;
  font-size: 17px;
}
#body {
  color: #000;
  color: rgba(0, 0, 0, 0.87);
  background-color: #FFF;
  width: 100%;
  padding: 10px 0;
  box-sizing: border-box;
  transition: height 2s ease-in-out;
}

#innerBody {
  height: 200px;
  background-color: orange;
}
<div id="wrapper">
  <div id="buttonContainer"><span id="buttonIcon">My</span><span id="buttonLabel">self</span>
  </div>
  <div id="content">
    <div id="heading">Press Me</div>
    <div id="body">
      <div id="innerBody"></div>
    </div>
  </div>
</div>
like image 186
Ori Drori Avatar answered Sep 27 '22 20:09

Ori Drori


Your initial max-height is set to 500px but the actual height is much less. In the transition, that 500px is gradually decreased towards 0. At first that has no visual effect, until the max-height becomes smaller then the actual height. this produces the "delay" you are seeing.

You should either transition the actual height property to 0 (but that only works if the initial height is set as well, to 200px in your case). Or you could look into transitioning a transform: scaleY(0), which has the added benefit of being much cheaper and giving a much smoother animation. (http://www.html5rocks.com/en/tutorials/speed/high-performance-animations/)

like image 36
Pevara Avatar answered Sep 27 '22 21:09

Pevara