2

I have an element which has display none on start. When i add a class to it i want it to fade in, using CSS.

I found this tutorial to use keyframes which is working nice for fade in. But if i want to fade out the same way, the element gets hidden immediately with no animation.

Basically it looks like this:

.box {
  display: none;
  opacity: 0;
  animation: FadeOut 1s ease-in-out;

  &.active {
    display: block;
    opacity: 1;
    animation: FadeIn 1s ease-in-out;
  }
}

Here is an "working" example: http://codepen.io/MickL/pen/NAopXN

2
  • As you see in the example, i animate it for fade in. Commented Aug 13, 2016 at 16:16
  • 1
    When you remove display: none in you .box selector, the animation becomes smooth, but the box won't collapse. Commented Aug 13, 2016 at 16:22

2 Answers 2

8

Trying to animate the display:none is the root of your problem. The confusion for why the fade-in works and the fade-out doesn't comes from the combination of using both display and opacity.

The display property is only being dictated by whether .active is applied; the animations aren't actually changing it, whereas the opacity is animated as expected. On the fade-in, this means that you immediately show your element, which then transitions from transparent to opaque. On the fade-out, this means that you immediately hide your element, which then transitions from opaque to transparent while hidden.

There are a couple different ways you could solve this, but it sort of depends on the context. For example, you could leave it as a block element and use the height property to make it collapse:

$('button').on('click', function(e) {
  e.preventDefault();
  $(this).siblings('.box').toggleClass('active');
})
@import "bourbon";
 * {
  box-sizing: border-box;
  text-align: center;
}
button {
  margin: 30px 0;
  border: 1px solid #ccc;
  text-align: center;
  padding: 1em;
  background: none;
  box-shadow: none;
}
.box {
  margin: 0 auto;
  width: 80%;
  height: 0;
  display: block;
  line-height: 100px;
  background: #ccc;
  border: 1px solid #444;
  text-align: center;
  opacity: 0;
  animation: FadeOut 1s ease-in-out;
}
.box.active {
  display: block;
  height: initial;
  opacity: 1;
  animation: FadeIn 1s ease-in-out;
}
@keyframes FadeIn {
  0% {
    opacity: 0;
    height: initial;
  }
  100% {
    opacity: 1;
    height: initial;
  }
}
@keyframes FadeOut {
  0% {
    opacity: 1;
    height: initial;
  }
  99% {
    opacity: 0;
    height: initial;
  }
  100% {
    height: 0;
    opacity: 0;
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="col">
  <button class="toggle-good">Toggle display</button>
  <p class="box good">I move nicely!</p>
  <p>Extra paragraph to show collapse</p>
</div>

Sign up to request clarification or add additional context in comments.

3 Comments

Only problem is that i see the fadeout-animation when the page loads :(
You could potentially fix that by putting the FadeOut animation on a separate class (e.g. inactive). Instead of toggling active, you would add and remove the two classes as needed.
Keep in mind that height: 0 keeps the element as part of the document tree, potentially tripping up e.g. keyboard users (tabbing onto items in the zero-height div) and assistive technologies like screen readers. I am not aware of a nice, neat, clean solution to this, but some JavaScript can help: codepen.io/alanhogan/pen/ExpyXQy
1

You can't animate or transition the display property.

Note: That's not to say you can't use it in keyframe animation but that's not the same as actually animating it.

The reason why your Codepen demo doesn't work as intended is because the .active class is being removed instantly so the animation out has no time to fire and the default display:none is now applied immediately.

Since you are using Jquery anyway, there is a built in function fadeToggle which will do what you want.

$('button').on('click', function(e) {
  e.preventDefault();
  $(this).siblings('.box').fadeToggle(500);
})
* {
  box-sizing: border-box;
  text-align: center;
}
button {
  margin: 30px 0;
  border: 1px solid #ccc;
  text-align: center;
  padding: 1em;
  background: none;
  box-shadow: none;
}
.box {
  margin: 0 auto;
  width: 80%;
  display: none;
  line-height: 100px;
  background: #ccc;
  border: 1px solid #444;
  text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="col">
  <button class="toggle-good">Toggle display</button>
  <p class="box good">I move nicely!</p>
</div>

5 Comments

No, you really didn't...it might look like it but it's not animatable. You can use it in a keyframe but it instantly switches from none to block
In the example i didnt used prefixes. This may not work in some browsers so you may not see it. I tested in chrome which doesn't need a prefix. if you add -moz- to animation and keyframes it will work ...
You don't understand, it's not animatable....but it can be used in an animation...that's not the same thing. The root cause of your problem is that the second fade animation never fires because the class is removed instantly...and the display reverts back to none instantly...because it can't be animated/transitioned.
The display property is not animatable at all according to the Formal Definition section on MDN docs: developer.mozilla.org/en-US/docs/Web/CSS/… Note this is unlike e.g. visibility which is treated as animating between 0 and 1 and which results in visibility for values greater than 0. So, display cannot be used in an @animation.
I am aware read my above comment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.