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>
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.
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).
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.
The animation-delay property specifies a delay for the start of an animation.
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>
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/)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With