DRB
DRB

Reputation: 653

Start Non-looping GIF from beginning with CSS only

I'd like to know if it's possible to start a non-looping GIF from the beginning with CSS animation? For my example I have two GIFs. The first counts 1,2,3 each second - the second GIF counts 4,5,6 each second.

My goal is to show the first GIF until it counts to 3, then switch to the second GIF until it counts to 6, where it stops. My issue is that the second GIF will always be on 6 if I get it to show, at all.

My setup is as follows:

<div id="gif-two" class="gif"></div>
<div id="gif-one" class="gif"></div>

CSS

.gif {
  width: 300px;
  height: 300px;
  position: absolute;
  top: 0;
  left: 50%;
  margin-left: -150px;
}

#gif-one {
  background: url("http://i.imgur.com/jLTVHdY.gif");
}

#gif-two {
  background: url("http://i.imgur.com/O61k5Nf.gif");
}

I'm at a loss on how to handle this at the moment. I've tried toggling visibility - but have no idea how to make this work in just CSS.

Upvotes: 2

Views: 3305

Answers (1)

Harry
Harry

Reputation: 89780

Note: It is possible to achieve what you want by using CSS animations (as you will see from this answer) but I'd recommend you to combine them into the same GIF and use it that way because the approach used in this answer is too complex (so much so that I may struggle to explain it).

When the GIF is added as abackground-image, both images are loaded at pretty much same time by the browser and the GIF animation starts executing immediately. This means that change from 4-5 on the second GIF is happening at almost the same time as 1-2 on the first GIF. So, when the first GIF's loop ends, the second GIF's loop would also have ended and this is why you'd always see only 6.

The only way to avoid that from happening is to make the browser load the image after the first loop is completed. Below snippet achieves just this in a very complicated manner. The below is how:

  • Initially the background image is added only to the first div (because it needs to start its own loop immediately).
  • An animation with duration of 3s is set to the first div. This animation will hide the first div (and its background image) after around 3s, which is, the time take for its loop to complete. The opacity change from 1 to 0 starts at 95% itself to create a fade-out effect. Otherwise, at the end of loop it looks as though it blinks off and the second GIF blinks on (which doesn't look pleasing).
  • The second div doesn't have any background image added to it at the start because if it is added then it will load immediately and start its loop. An animation with 3s duration is added to this also.
  • The animation on the second div is such that it gets the background image added to it only at the end of the animation (100%). This means that the second image is loaded only after 3s (duration) and it starts its loop only from that time (by which, the loop of the first is already completed).

.gif {
  width: 300px;
  height: 300px;
  position: absolute;
  top: 0;
  left: 50%;
  margin-left: -150px;
}

#gif-one {
  animation: img 3s linear forwards;
  background: url(http://i.imgur.com/jLTVHdY.gif?3);
}

#gif-two {
  animation: img2 3s linear forwards;
  z-index: -1;
}

@keyframes img {
  0%, 95% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

@keyframes img2 {
  0%, 99% {
    background-image: none;
  }
  100%{
    background: url(http://i.imgur.com/O61k5Nf.gif?3);    
  }  
}
<div id="gif-one" class="gif"></div>
<div id="gif-two" class="gif"></div>


Note: As I was writing this answer, I realized that setting the background-image within @keyframes rules does not work in IE and Firefox. Hence, the above solution is WebKit only. Also, as far as I am aware there is no other pure CSS solution possible. You would have to use JavaScript and that would help in the cache busting that CBroe is referring to also. Below is a sample demo using JS.

Using single element + JS:

window.onload = function() {
  var el = document.querySelector('.gif');
  el.style.backgroundImage = 'url(http://i.imgur.com/jLTVHdY.gif' + Math.random() + ')';
  setTimeout(function() {
    el.style.backgroundImage = 'url(http://i.imgur.com/O61k5Nf.gif' + Math.random() + ')';
  }, 3250);
}
.gif {
  width: 300px;
  height: 300px;
  position: absolute;
  top: 0;
  left: 50%;
  margin-left: -150px;
}
<div class="gif"></div>

Using two elements + JS:

window.onload = function() {
  var el1 = document.querySelector('#gif-one'),
      el2 = document.querySelector('#gif-two');
  el1.style.backgroundImage = 'url(http://i.imgur.com/jLTVHdY.gif' + Math.random() + ')';
  setTimeout(function() {
    el1.style.opacity = '0';
    el2.style.backgroundImage = 'url(http://i.imgur.com/O61k5Nf.gif' + Math.random() + ')';
  }, 3250);
}
.gif {
  width: 300px;
  height: 300px;
  position: absolute;
  top: 0;
  left: 50%;
  margin-left: -150px;
  transition: opacity .05s .5s;
}
<div id="gif-one" class="gif"></div>
<div id="gif-two" class="gif"></div>

Upvotes: 2

Related Questions