24

I have div with id='mainmenu'. I'm adding CSS3 transition to it by JavaScript after button click (by adding 'transition' to #mainmenu and by creating class .fadein and .fadeout that will be added to the div element). Code:

<div id='mainmenu'></div>
<button id="btn1">Click me1</button>
<button id="btn2">Click me2</button>

#mainmenu {
    width:100px; 
    height:100px; 
    background:#eee; 
    -webkit-transition: opacity 1s; 
    -moz-transition: opacity 1s; 
    transition: opacity 1s; 
}

.fadeout {
    opacity:0;
}
.fadein {
    opacity:1;
}


var menu = document.getElementById('mainmenu'),
    btn1 = document.getElementById('btn1'),
    btn2 = document.getElementById('btn2');

btn1.addEventListener('click', function() {
    menu.className = 'fadeout';
}
btn2.addEventListener('click', function() {
    menu.className = 'fadein';
}

The problem is that now I want to add display none and block to fadeout and fadein option. So after the fadeout animation div should get display none, and after fadein display block:

btn1.addEventListener('click', function() {
    menu.className = 'fadeout';
    menu.style.display = 'none';
}
btn2.addEventListener('click', function() {
    menu.className = 'fadein';
    menu.style.display = 'block';
}

Unfortunately, the display none and block executes with the animation, so the animation isn't working (element gets display none, without the opacity animation). I want first the animation with opacity, and after that display none/block for the element. Is there any way to do it? I can use only pure JavaScript (no jQuery etc.).

Amay
  • 1,461
  • 5
  • 27
  • 56

4 Answers4

18

You need to use setTimeout() with menu.style.display = "none"; in order to let fade do it's job before you trigger style.display.

btn1.addEventListener('click', function() {
    menu.className = 'fadeout';
    setTimeout(function() {
        $(menu).css('display', 'none');
    }, 1000);
}
btn2.addEventListener('click', function() {
    menu.className = 'fadein';
    setTimeout(function() {
        $(menu).css('display', 'block');
    }, 1000);
}
Timo Tijhof
  • 10,032
  • 6
  • 34
  • 48
bogatyrjov
  • 5,317
  • 9
  • 37
  • 61
  • There is a small problem - when you have 'menu' in setTimeout(function(menu){}), the console shows 'Cannot read property 'style' of undefined'. Removing 'menu' from function will fix that problem. Thank you for help. – Amay Sep 03 '13 at 22:08
  • of course, hesitated about whether to include that for a sec the first time and made a mistake – bogatyrjov Sep 03 '13 at 22:13
  • Curious about which browser supports .hide()/.show() - In chrome you would get `Uncaught TypeError: Object # has no method 'hide'` – dc5 Sep 03 '13 at 22:40
  • dc5 - in your case, it's probably a problem of jQuery library not being included, or a conflict with another library. If you use other libraries, try using "jQuery" instead of "$". Another possibility is that you are passing the wrong object. There is an example here : http://api.jquery.com/hide/ , which works on my chrome. – bogatyrjov Sep 03 '13 at 23:32
  • @JevgeniBogatyrjov: The problem was the answer code using the same variable name ('menu') for both the DOM Node ('menu.className') and jQuery ('menu.hide'). Fixed :) – Timo Tijhof Feb 04 '15 at 21:32
11

Although this is an old post, for future visitor's sake, you can use the transitionend event. You can use:

/*For when object has fully faded*/
menu.addEventListener("transitionend", function() {
  if (this.className == "fadeout") {
    this.style.display = "none";
  }
}.bind(menu));

/*Show before animation starts*/
menu.addEventListener("click", function() {
  this.style.display = "block";
}.bind(menu));
Darrennchan8
  • 192
  • 4
  • 8
10

I could be wrong here, however i believe you need to add a transition-end trigger that does the display:block / display:none change.

see: CSS3 transition events

Community
  • 1
  • 1
Robert
  • 386
  • 1
  • 8
8

I use height 0 instead of display none for some cases but It may or may not apply for what you need. Anyway here's the code:

1) Using transitions (looks like jQuerys fadeOut):

.fadeOut{
  opacity : 0;
  height : 0;
  transition : opacity 800ms, height 0 800ms;
}

if you want you can add width 0 too.

.fadeOut{
  opacity : 0;
  width : 0;
  height : 0;
  transition : opacity 800ms, height 0 800ms, width 0 800ms;
}

2) Using animations (it works but transitions is better):

.fadeOut{
  animation : fadeout 800ms linear forwards;
}
@keyframes fadeout{
  99%{
    opacity : 0;
    height : initial;
  }
  100%{
    opacity : 0;
    height : 0;
  }
}
Erick A. Montañez
  • 447
  • 1
  • 6
  • 11