1

My solution: I changed the display styles to visibility styles because this solution suited my webpage best. Many other solutions can be found by Googling "display block overrides animation". The accepted answer is the one that gave me the keywords so I could use Google.


Original post:

Fiddle here

I've made fadeIn and fadeOut functions to animate the opacity using CSS animations rather than JQuery animations. Clicking on the image should make a popup fade in and the image fade out over 300ms. Clicking anywhere in the body should make the popup fade out and the image fade in over 300ms.

At the moment the fadeOut works, but fadeIn seems to ignore the transition time, and instantly appears. Why isn't fadeIn working?

JavaScript:

function fadeIn(elem) {
    elem.css("display", "block");
    elem.css("opacity", 1);
}

function fadeOut(elem) {
    elem.css("opacity", 0);
    setTimeout(function() {
        elem.css("display", "none");
    }, 300);
}

$("body").on("click", function(ev) {
      if (ev.target != $("#btn")[0] && $("#popup").is(":visible")) {
        fadeIn($("#btn"));
        fadeOut($("#popup"));
    }
});

$("#btn").on("click", function(ev) {
    fadeIn($("#popup"));
    fadeOut($("#btn"));
});

CSS:

#btn {
    position: absolute;
    top: 100px;
    left: 10px;
    transition: 0.3s;
    opacity: 1;
}

#popup {
    position: absolute;
    background-color: black;
    display: none;
    color: red;
    z-index: 1;
    padding: 0 1em;
    transition: 0.3s;
    opacity: 0;
}

DarkMatterMatt
  • 486
  • 8
  • 17

2 Answers2

4

The problem is when you use display: block/display: none, and when removed, it works

  function fadeIn(elem) {
  /*
    elem.css("display", "block");
  */    
    elem.css("opacity", 1);
  }

  function fadeOut(elem) {
    elem.css("opacity", 0);
    /*
    setTimeout(function() {
      elem.css("display", "none");
    }, 1300);
    */
  }

  $("body").on("click", function(ev) {
    if (ev.target != $("#btn")[0] && $("#popup").is(":visible")) {
      fadeIn($("#btn"));
      fadeOut($("#popup"));
    }
  });

  $("#btn").on("click", function(ev) {
    fadeIn($("#popup"));
    fadeOut($("#btn"));
  });
body {
  height: 10vh;
  width: 10vw;
}

#btn {
  position: absolute;
  top: 100px;
  left: 10px;
  transition: 1.3s;
  opacity: 1;
}

#popup {
  position: absolute;
  background-color: black;
  color: red;
  z-index: 1;
  padding: 0 1em;
  transition: 1.3s;
  opacity: 0;
}
<img id="btn" src="http://via.placeholder.com/150x150">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.js"></script>
<script src="https://new.matt.cat/scipad-app/jquery.hammer.js"></script>
<div id="popup">
  <p>
    click here to close popup
  </p>
</div>
Ason
  • 79,264
  • 11
  • 79
  • 127
  • 1
    Do you know why `display` affects it like this? Shouldn't it start the animation *after* the `display: block` is set? – DarkMatterMatt May 31 '17 at 20:29
  • @DarkMatterMatt It is how `display: block` works, so when you set `elem.css("display", "block");` it simply overrides the animation. What you could do, is to add a timeout for that as well, as what is needed is to force the browser to redraw that area. Here is a post describing this some more: https://stackoverflow.com/questions/8840580/force-dom-redraw-refresh-on-chrome-mac – Ason May 31 '17 at 20:32
  • Is this JQuery being "helpful"? I seem to remember setting it through JavaScript (`elem.style.display = "block"`) doesn't do this? Maybe I remember incorrectly. – DarkMatterMatt May 31 '17 at 20:34
  • @DarkMatterMatt Nope, does not matter which you use...see previous comments link – Ason May 31 '17 at 20:35
  • Thanks, didn't see the link, I did find this post though: https://stackoverflow.com/a/17191375/6595777 – DarkMatterMatt May 31 '17 at 20:38
  • @DarkMatterMatt That is another way, if you really need `display: block`. 1: Have you tested it cross browsers ? .... 2: Why do you need `display: block`? – Ason May 31 '17 at 21:04
  • 1
    Thanks for your help, I changed `display` to `visibility` and it works fine for me (the absolute positions mean that it doesn't interfere with the page flow) – DarkMatterMatt May 31 '17 at 22:06
0

Possibly try

transition: opacity 0.3s;

https://www.w3schools.com/css/css3_transitions.asp

  function fadeIn(elem) {
    elem.css("display", "block");
    elem.css("opacity", 1);
  }

  function fadeOut(elem) {
    elem.css("opacity", 0);
    setTimeout(function() {
      elem.css("display", "none");
    }, 300);
  }

  $("body").on("click", function(ev) {
    if (ev.target != $("#btn")[0] && $("#popup").is(":visible")) {
      fadeIn($("#btn"));
      fadeOut($("#popup"));
    }
  });

  $("#btn").on("click", function(ev) {
    fadeIn($("#popup"));
    fadeOut($("#btn"));
  });
body {
  height: 10vh;
  width: 10vw;
}

#btn {
  position: absolute;
  top: 100px;
  left: 10px;
  -webkit-transition: 0.3s;
  transition: 0.3s;
  opacity: 1;
}

#popup {
  position: absolute;
  background-color: black;
  display: none;
  color: red;
  z-index: 1;
  padding: 0 1em;
  -webkit-transition: opacity 0.3s;
  transition: opacity 0.3s;
  opacity: 0;
}
<img id="btn" src="http://via.placeholder.com/150x150">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.js"></script>
<script src="https://new.matt.cat/scipad-app/jquery.hammer.js"></script>
<div id="popup">
  <p>
    click here to close popup
  </p>
</div>
k2snowman69
  • 1,518
  • 8
  • 16
  • Thanks, I'm out at the moment, but testing in my fiddle it doesn't seem to change – DarkMatterMatt May 31 '17 at 20:31
  • Yea, I missed the display none/block that @LGSon picked up. That said, probably still not a bad idea to stick with standards as transitions (based off spec) should be `transition: property time` and you can use `all` for property which will animate any animatable property. – k2snowman69 Jun 02 '17 at 19:51