Recursive function to change opacity (efect fadein with pure js)

76 views Asked by At

Why this code is not changing opacity value in progress?

function fadeIn(arg_idElemHtml,arg_opacityValue) {
    if(arg_opacityValue < 1){
      var objHtml = document.getElementById(arg_idElemHtml);
      objHtml.style.display = 'block';
      objHtml.style.opacity = arg_opacityValue + 0.1;
      arg_opacityValue = parseFloat(arg_opacityValue) + 0.1;
      setTimeout(fadeIn(arg_idElemHtml,arg_opacityValue), 400);
    }
}
#msg {background-color:red;display:none;opacity:0.0}
<button id="bt" onclick="fadeIn('msg',0);">GO</button>
<div id="msg">content message</div>

2

There are 2 answers

4
pilchard On BEST ANSWER

Here is an example to illustrate my comment regarding using CSS to handle the fade in on click.

I've used addEventListener() instead of inline handler assignment which is generally recommended. I have also used classes to define the re-usable fade related CSS. This avoids duplication if you are going to reuse the functionality as well as resolving specificity issues that arise in mixing id and class based style assignments.

const bt = document.getElementById('bt');

bt.addEventListener('click', () => fadeIn('msg'));

function fadeIn(id) {
  const objHTML = document.getElementById(id);
  objHTML.classList.toggle('hidden');
}
#msg {
  background-color: red;
}

.fade-in {
  display: block;
  animation: fadeInAnimation 2s;
}

.hidden {
  display: none;
}

@keyframes fadeInAnimation {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
<button id="bt">Go</button>
<div id="msg" class="fade-in hidden">content message</div>

For extended discussion see:

Transitions on the CSS display property.

Take the time to read through all the answers, the top voted or accepted answer may not be the most relevant to your situation.

Edit - Fade Out

It is a little more involved to add a fade out effect, since you don't want to set display: none; until the animation is complete. Here is an example using the animationend event to cleanup/complete the transition.

Whether showing or hiding the element we first add a listener on the animationend event that will cleanup the classes added to handle the animation. When adding the listener it is important to pass an options object with {once: true} which will remove the listener after the first time it runs. This is to ensure we don't create multiple listeners on the same element.

Having added the cleanup listener we proceed to add the relevant fade class — If the element is hidden we add the fade-in class and remove the hidden class, otherwise we add the fade-out class to begin the animation. You'll note that we are reusing the same keyframes CSS by using the animation-direction property to reverse it in the fade-out class.

const bt = document.getElementById("bt");

bt.addEventListener("click", () => fade("msg"));

function fade(id) {
  const objHTML = document.getElementById(id);

  if (objHTML.classList.contains("hidden")) {
    const fadeInCleanup = () => {
      objHTML.classList.remove("fade-in");
    };

    objHTML.addEventListener("animationend", fadeInCleanup, { once: true });

    objHTML.classList.add("fade-in");
    objHTML.classList.remove("hidden");
  } else {
    const fadeOutCleanup = () => {
      objHTML.classList.remove("fade-out");
      objHTML.classList.add("hidden");
    };

    objHTML.addEventListener("animationend", fadeOutCleanup, { once: true });

    objHTML.classList.add("fade-out");
  }
}
#msg {
  background-color: red;
}

#next-msg {
  background-color: pink;
}

.block {
  display: block;
}

.fade-in {
  animation-name: fade;
  animation-duration: 2s;
}

.fade-out {
  animation-name: fade;
  animation-duration: 2s;
  animation-direction: reverse;
}

.hidden {
  display: none;
}

@keyframes fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
<button id="bt">Go</button>
<div id="msg" class="block hidden">fading message</div>
<div id="next-msg">persistent message</div>

0
Red On

That is because you set the callback in setTimeout wrong.

function fadeIn(arg_idElemHtml,arg_opacityValue) {
    if(arg_opacityValue < 1){
      var objHtml = document.getElementById(arg_idElemHtml);
      objHtml.style.display = 'block';
      objHtml.style.opacity = arg_opacityValue + 0.1;
      
      arg_opacityValue = parseFloat(arg_opacityValue) + 0.1;
      
      // Like this
      setTimeout(() => fadeIn(arg_idElemHtml,arg_opacityValue),400);
      
      // Or
      // setTimeout(fadeIn.bind(this, arg_idElemHtml,arg_opacityValue),400);
    }
}
#msg {background-color:red;display:none;opacity:0.0}
<button id="bt" onclick="fadeIn('msg',0);">GO</button>
<div id="msg">content message</div>