I’m a big fan of Travis Neilson and his DevTips YouTube Channel. He comes across as a genuine, honest and all-round nice guy, and he shares some pretty useful tips and tutorials around design and front-end development.

Earlier in the week, I came across his video called Build-in Load Animation as part of his CSS Animation series. I was looking to do something similar on my photo gallery, just to add some visual interest.

If you watch the video, Travis begins with a ready-built image gallery, using the popular Masonry jQuery library to create a pinterest style layout. The way that he achieves the build-in animations is by using jQuery to loop around all the items in the gallery and add a class to it. To get these to animate one at a time, he sets a time delay when adding the class. The class has an animation CSS rule associated with it, so when the class is added to the element, the animation is triggered. It looks pretty cool.

I really wanted to implement this on my site, but I didn’t want to use JavaScript to do it. The code on my site is quite clean and lightweight (at the time of writing!), and the only things I use JavaScript for is Google Analytics and Disqus Comments. So I went about trying to do this by just using HTML and CSS - no JavaScript - in the most efficient way that I could.

In my example, I made use of loops in the Liquid templating engine used in Jekyll (the static site generator used to built this site), and also an index loop in Sass in order to create the specific classes needed to build the animations, each with their appropriate delay. There is nothing complicated here.

So here’s the code! (and don’t forget to check my photo gallery to see it in action)

The HTML (Liquid)

<ul class="photo-gallery">
  {% for photo in site.photos %}
    <li class="photo-thumb photo-{{ forloop.index }}">
      <a href="{{ photo.url | prepend: site.baseurl }}">
        <img src="{{ site.baseurl }}/assets/photographs/thumbnails/{{ photo.image }}" alt="{{ photo.title }}" />        
      </a>
    </li>
  {% endfor %}
</ul>

Here’s the HTML for the my photo gallery. It’s an unordered list in which I loop around a collection of photos and display an image link inside each list item. In Liquid, you can access the index of the iteration by using the forloop.index variable. This is appended to photo- to create a reference a unique class for that list item (line 3 of the code), for example, photo-1, photo-2, photo-3 and so on. We can now create a CSS animation with an appropriate delay for each item.

The CSS (Sass)

Animation

@keyframes drop {
  0% {
    opacity: 0;
    transform: scale(1.4);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

The code above defines the animation. At the start (0%) of the animation, the photo item should still not be visible, so the opacity is set to zero. In order to achieve an effect of the photo “dropping” on to the page, I set the scale to 1.4. A scale of 1 is the element’s normal size, so in this instance it is 0.4 times bigger than normal, which gives it the effect of being closer to the user.

At the end (100%) of the animation, the photo item should be fully visible (full opacity), so I set opacity to 1. To finish the “drop” effect, the element should be set back to its normal size, so I set the scale back to 1. The transition of the scale going from 1.4 to 1 makes it look like the element is dropping onto the page.

Managing the delays

$items-to-animate: 12;
$delay-milliseconds: 200;

.photo-thumb {
  opacity: 0;

  @for $i from 1 through $items-to-animate {
    &.photo-#{$i} {
      animation: drop 400ms ease-in-out #{$i * 200}ms forwards;
    }
  }
}

Creating a CSS rule for each photo in a gallery would normally be an exercise in copy and pasting, leading to a lot of repeated code and something difficult to maintain and change. With Sass we can perform loops, use variables, and calculate values to create something that’s easy to read and maintain.

To start, all the photos in the gallery should not be visible, so the opacity is set to zero. The next bit is where the usefulness of Sass comes in. We start off with a for loop from 1 to 12 - this is the number of photos I display per page of the gallery. I then define rules for each of the unique classes that we created in the HTML document. I do this by outputting the value of the index of the iteration by using #{$i} which I append to photo-. Within this rule, I use the animation shorthand property to specify the name of the @keyframe we defined earlier (which is drop), the duration the animation takes from start to finish, the timing function and most importantly the delay before the animation starts. This is the output of a calculation which takes the number of the current index multiplied by 200 milliseconds. Finally we specify the fill mode which determines what values are applied by the animation outside the time it is executing. By using forwards the animation will apply the property values for the time the animation ended.

That’s all it is!

Summary

I’m pleased that I managed to get this cascading animation effect working without having to use JavaScript. That’s not to say that I don’t like JavaScript; You can do awesome things that is just not possible with HTML, CSS, SVGs and images alone.

There are a few pros and cons. First of all, the amount of lines of JavaScript needed to create this affect is around five, and the amount of lines of Sass needed is also around five; however, the Sass compiles into 24 lines of CSS (in its un-minified state), so it does add a bit more weight to your production code. But if you are using Sass, you are probably already minifying your CSS anyway so the difference in bytes is going to be negligible.

Secondly, the JavaScript will cater for all the elements on the page with a specific class. You can just add more elements to the page later, and the animations will just work. The CSS solution works best with a set number of items, as you have to specify in the Sass how many items to animate. But is actually a drawback? If your goal is to animate elements on page load only, then do you care if elements that are “below the fold” (that is, outside of the browsers viewport) animate or not if the user can’t see it? This way, you could specify a safe number of elements to animate if you were confident about a maximum number of elements that would be visible when you navigate to the page. This may cause an issue if you use the back button on your browser as it will take you back to the scrolled position of the page.

When using CSS animation there is always a risk that the animation will begin before the image has fully loaded, and there is no way to get around that without using JavaScript. One option is to use the imagesLoaded plugin that was authored by the same people who created the Masonry plugin. That way, you can wait until all the images have fully loaded before animating them one by one. I personally haven’t seen any issues with my implementation, but I have pretty quick download speeds with my broadband at home, and 4G in a lot of places out and about in South Wales.

I hope that this short snippet of Sass comes in useful for you in your next project! Feel free to leave any tips and tricks in the comment section. :-)