Skip to content
Advertisement

Change of pictures over and over by using setInterval

Below is a program that is to loop pictures with fade-in effect.

It includes this statement:

opacity = Number(window.getComputedStyle(abc).getPropertyValue("opacity")); 

I understand that this statement assigns the opacity value of a window object to a variable opacity, but there is no such opacity variable declaration of any elements in the program!

When I remove this statement, it only shows the first picture… And when I keep that statement, the program loops well with a fade-in effect.

Can anyone explain to me why such phenomenon happens?

Compare these two snippets:

  1. With assignment to opacity (fading is working as expected):

var opacity = 0;
var arrindex = 0;
var arr1 = [
  "https://via.placeholder.com/400x400?text=p1", 
  "https://via.placeholder.com/400x400?text=p2", 
  "https://via.placeholder.com/400x400?text=p3", 
  "https://via.placeholder.com/400x400?text=p4", 
  "https://via.placeholder.com/400x400?text=p5" 
];

setInterval(changepcs, 3000);

function changepcs() {
  if (arrindex == arr1.length) {
    arrindex = 0
  };
  let abc = document.getElementById("picture");
  let address = arr1[arrindex];
  abc.style.backgroundImage = `url(${address})`;
  abc.classList.remove("fadein");
  opacity = window.getComputedStyle(abc).getPropertyValue("opacity");
  abc.classList.add("fadein");
  arrindex++;
}
body {
  height: 100vh;
}

#picture {
  background-repeat: no-repeat;
  background-position: center;
  background-size: 400px 400px;
  width: 80%;
  margin: auto;
  height: 80%;
  opacity: 0;
}

#picture.fadein {
  opacity: 1;
  transition: opacity 2s linear;
}
<div id="picture"></div>
  1. Without assignment to opacity (no fading effect for second image):

var opacity = 0;
var arrindex = 0;
var arr1 = [
  "https://via.placeholder.com/400x400?text=p1", 
  "https://via.placeholder.com/400x400?text=p2", 
  "https://via.placeholder.com/400x400?text=p3", 
  "https://via.placeholder.com/400x400?text=p4", 
  "https://via.placeholder.com/400x400?text=p5" 
];

setInterval(changepcs, 3000);

function changepcs() {
  if (arrindex == arr1.length) {
    arrindex = 0
  };
  let abc = document.getElementById("picture");
  let address = arr1[arrindex];
  abc.style.backgroundImage = `url(${address})`;
  abc.classList.remove("fadein");
  // opacity = window.getComputedStyle(abc).getPropertyValue("opacity");
  abc.classList.add("fadein");
  arrindex++;
}
body {
  height: 100vh;
}

#picture {
  background-repeat: no-repeat;
  background-position: center;
  background-size: 400px 400px;
  width: 80%;
  margin: auto;
  height: 80%;
  opacity: 0;
}

#picture.fadein {
  opacity: 1;
  transition: opacity 2s linear;
}
<div id="picture"></div>

Advertisement

Answer

The difference is not related to the variable opacity: you are right; it’s value is never used after that assignment and is therefore unnecessary.

However, the call of getComputedStyle(abc).getPropertyValue("opacity") still makes the difference — you can omit the call of Number and the assignment of this expression without any negative consequence, but the expression must stay.

This getComputedStyle(abc).getPropertyValue("opacity") is a complex API: it needs to render the document to know exactly what the opacity value is, since in general such CSS values can be influenced by a lot of CSS rules. My hunch is that the engine performs a paint cycle in order to compute the real, rendered value of this property. That means the execution of this call takes some time — at least until after the next paint cycle. The side effect of this paint job is that the removal of the fadein class has now also been rendered. And that means that when that fadein class is added again, it really triggers the animation.

Without this getComputedStyle(abc).getPropertyValue("opacity") evaluation, the engine does not wait for a paint cycle. That means it has not yet effectuated the class removal when it adds the fadein class again. By consequence, nothing really changes — the fadein class was still applied on the rendering when it is already “added” again. That means there is no animation.

I was a bit puzzled by this effect of that expression too. I would have explicitly waited for a paint cycle to happen with the call to requestAnimationFrame so to execute code right before the next paint cycle, and then schedule a callback again to get code to execute after the next paint job (before the next one). That would be the moment I would be sure the CSS class fadein had been removed in the rendered document and it would be the right time to add it again — so triggering the animation.

Like so:

var arrindex = 0;
var arr1 = [
  "https://via.placeholder.com/400x400?text=p1", 
  "https://via.placeholder.com/400x400?text=p2", 
  "https://via.placeholder.com/400x400?text=p3", 
  "https://via.placeholder.com/400x400?text=p4", 
  "https://via.placeholder.com/400x400?text=p5" 
];

setInterval(changepcs, 3000);

function changepcs() {
  if (arrindex == arr1.length) {
    arrindex = 0
  };
  let abc = document.getElementById("picture");
  let address = arr1[arrindex];
  abc.style.backgroundImage = `url(${address})`;
  abc.classList.remove("fadein");
  // Need to wait for a paint cycle to occur before 
  //    adding the CSS class again
  requestAnimationFrame(() => 
    requestAnimationFrame(() => abc.classList.add("fadein"))
  );
  arrindex++;
}
body {
  height: 100vh;
}

#picture {
  background-repeat: no-repeat;
  background-position: center;
  background-size: 400px 400px;
  width: 80%;
  margin: auto;
  height: 80%;
  opacity: 0;
}

#picture.fadein {
  opacity: 1;
  transition: opacity 2s linear;
}
<div id="picture"></div>
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement