1

I am trying to animate in divs with each having 1 transparent image inside. once the image is loaded in i want it to gradually change opacity from 0 to 1. I made most of it work but still somewhere some code is wrong since the images dont get any change at all.

Does anybody know what is wrong or how to fix it.

If code snipplet isnt ok with you here is link to jsfiddle

var items = document.querySelectorAll(".item"),
  t = 0;

items.forEach(function(i) {
  i.style.animationDelay = t + "s";
  t = t + 0.05;
});

var imgs = [];

items.forEach(function(itm) {
  imgs.push(itm.children[0]);
});


for (var i = 0; i < imgs.length; i++) {
  imgs[i].onload = () => {imgs[i].style.opacity = "1";};
}
body {
  background: #212121;
}

.list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.item {
  transform: scale(0);
  width: 150px;
  height: 210px;
  margin: 1%;
  box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.7);
  background: #191919;
  cursor: pointer;
  border-radius: 2px;
  animation: 0.2s loadInItems ease forwards;
}

.item img {
  opacity: 0;
  height: 100%;
  width: 100%;
  border-radius: 2px;
}

@keyframes loadInItems {
  from {
    opacity: 0;
    transform: scale(0);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes fadeIn {
  to {
    opacity: 1
  }
}
<div class="list">
  <div class="item">
    <img src="https://bo3li.files.wordpress.com/2011/05/drive-angry-movie-cover.jpg">
  </div>

  <div class="item">
    <img src="http://www.tolkienlibrary.com/press/images/movie-tie-in-The-hobbit.jpg">
  </div>

  <div class="item">
    <img src="http://netdna.webdesignerdepot.com/uploads/2011/02/jurassicpark.jpg">
  </div>

  <div class="item">
    <img src="http://posterwire.com/wp-content/uploads/lord_of_war.jpg">
  </div>

  <div class="item">
    <img src="https://davebrendon.files.wordpress.com/2010/12/i-am-number-four-movie-poster.jpg">
  </div>

  <div class="item">
    <img src="http://gdj.gdj.netdna-cdn.com/wp-content/uploads/2011/12/grey-movie-poster.jpg">
  </div>

  <div class="item">
    <img src="https://s-media-cache-ak0.pinimg.com/originals/e2/81/9d/e2819de0653c516f0e242038770fa3b8.jpg">
  </div>

  <div class="item">
    <img src="http://netdna.webdesignerdepot.com/uploads/2011/02/inception.jpg">
  </div>

  <div class="item">
    <img src="https://bo3li.files.wordpress.com/2011/05/drive-angry-movie-cover.jpg">
  </div>

  <div class="item">
    <img src="http://www.tolkienlibrary.com/press/images/movie-tie-in-The-hobbit.jpg">
  </div>

</div>

Idk if i explained it well enough:

  1. divs are there since the beginning as well as images (but images naturally load after the divs)
  2. divs then get animated from scale and opacity 0 to both 1.
  3. at soon as each of the images is loaded-in that image fades from opacity 0 to 1
The Truth
  • 63
  • 10

2 Answers2

0

As explained here the onLoad event may be fired to early when the image is retrieved from the browser cache. I adopted the hack he proposed for your code, replace the last for loop with it.

const onImageLoadHandler = () => {
    imgs[i].style.opacity = "1";
}

for (var i = 0; i < imgs.length; i++) {
  imgs[i].onload = onImageLoadHandler;
  if (imgs[i].complete) onImageLoadHandler()
}

fiddle

Community
  • 1
  • 1
schrej
  • 450
  • 3
  • 10
0

So, your problem is that you're hooking on the onload event too late. This happens because your code runs after the DOM creation. Think of it this way: When your code is evaluated, the browser already evaluated the image source attribute and most likely has already fired the onload event.

You can solve this by simply making use of custom attributes and getAttribute(). So, first we change the src attribute from your images to a lazy-src one. This way, the browser will know that there's an image, but its source is unknown - therefore it wont fire the onload.

Then, when you are looping through your items; instead of pushing that item into an array, you change its srcattribute to that of the value from lazy-src and thats when you hook the onload to change your element style: (here's a link to your updated fiddle)

 var items = document.querySelectorAll(".item"),
  t = 0;

items.forEach(function(i) {
  i.style.animationDelay = t + "s";
  t = t + 0.05;
});

var imgs = [];

items.forEach(function(itm) {
  let image = itm.children[0]
  image.src = image.getAttribute('lazy-src');
  image.onload = () => {
    image.style.opacity = "1";
  };
});
body {
  background: #212121;
}

.list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.item {
  transform: scale(0);
  width: 150px;
  height: 210px;
  margin: 1%;
  box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.7);
  background: #191919;
  cursor: pointer;
  border-radius: 2px;
  animation: 0.2s loadInItems ease forwards;
}

.item img {
  opacity: 0;
  height: 100%;
  width: 100%;
  border-radius: 2px;
}

@keyframes loadInItems {
  from {
    opacity: 0;
    transform: scale(0);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes fadeIn {
  to {
    opacity: 1
  }
}
<div class="list">
  <div class="item">
    <img lazy-src="https://bo3li.files.wordpress.com/2011/05/drive-angry-movie-cover.jpg">
  </div>

  <div class="item">
    <img lazy-src="http://www.tolkienlibrary.com/press/images/movie-tie-in-The-hobbit.jpg">
  </div>

  <div class="item">
    <img lazy-src="http://netdna.webdesignerdepot.com/uploads/2011/02/jurassicpark.jpg">
  </div>

  <div class="item">
    <img lazy-src="http://posterwire.com/wp-content/uploads/lord_of_war.jpg">
  </div>

  <div class="item">
    <img lazy-src="https://davebrendon.files.wordpress.com/2010/12/i-am-number-four-movie-poster.jpg">
  </div>

  <div class="item">
    <img lazy-src="http://gdj.gdj.netdna-cdn.com/wp-content/uploads/2011/12/grey-movie-poster.jpg">
  </div>

  <div class="item">
    <img lazy-src="https://s-media-cache-ak0.pinimg.com/originals/e2/81/9d/e2819de0653c516f0e242038770fa3b8.jpg">
  </div>

  <div class="item">
    <img lazy-src="http://netdna.webdesignerdepot.com/uploads/2011/02/inception.jpg">
  </div>

  <div class="item">
    <img lazy-src="https://bo3li.files.wordpress.com/2011/05/drive-angry-movie-cover.jpg">
  </div>

  <div class="item">
    <img lazy-src="http://www.tolkienlibrary.com/press/images/movie-tie-in-The-hobbit.jpg">
  </div>

</div>
MoshMage
  • 506
  • 5
  • 30
  • Thanks a lot man. But will the lazy tag stay in the code? And is there a way to remove it from the img once the whole loading animation thing is done? See i want to be able to load in for example an adittional group of theese items lets say 5 of them to the end of the list and i want them to get the same animation when they load in and not animate all elements again. – The Truth Jan 24 '17 at 15:03
  • Sure you can, just use `image.removeAttribute('lazy-src')` when you're done with the `onload` event :) – MoshMage Jan 24 '17 at 15:04
  • :) thanks man you've been a great help. i wouldnt find theese weird attributes for some time. – The Truth Jan 24 '17 at 15:10
  • ahh there is one problem. it all works fine besodes the images load in gradually like i went to throttle the connection (chrom devtools) and i saw how they load in lines. what i need is for them to "fade in" using opacity 0 - 1 when they are fully loaded. – The Truth Jan 24 '17 at 15:27
  • @TheTruth that's not the code fault... That's how every images is loaded in the browser, see [this question](http://stackoverflow.com/questions/33895331/why-do-images-on-the-web-load-line-by-line) or [this one](http://stackoverflow.com/questions/11741487/prevent-progressive-line-by-line-loading-of-background-image). – MoshMage Jan 24 '17 at 15:33
  • What about something similar to this? http://stackoverflow.com/a/3016076 – The Truth Jan 24 '17 at 15:43
  • 1
    my bad i screwed up 1 line i just had to give the image the default value of opacity:0 and now it works perfectly fine. – The Truth Jan 24 '17 at 19:01