Inspired by a popular Mac OS X screensaver theme and using the incredible photographs of Liam Wong, I’ve made this automated presentation for sites, suitable for portfolios and marketing. It combines some of the oldest principles of web development - progressive enhancement - with some of the newest: the Web Animation API.
Step By Step
While I will be using a polyfill to gain support for the Web Animation API in browsers other than Chrome and Firefox, it’s important to build the interaction as if JavaScript won’t work at all. To that end, the images are placed on the page as follows (alt
values have been left blank for conciseness and clarity)
<div class="shuffle reveal">
<img src="umbrellas.jpg" alt>
<img src="shopping-at-night.jpg" alt>
<img src="lanterns.jpg" alt>
<img src="outdoor-dining.jpg" alt>
<img src="blade-runner.jpg" alt>
<img src="square-umbrellas.jpg" alt>
</div>
If we assume that the basic CSS loads, the images should be styled in rows, using a variation on the technique I discussed in the last article:
@keyframes reveal {
to {
opacity: 1;
}
}
.shuffle {
min-height: 100vh;
position: relative;
}
.shuffle img {
width: 33%;
opacity: 0;
transform: scale(1.3);
}
.reveal img {
animation: reveal 1s 1s forwards;
}
The <div>
is set to a min-height
with vh
units and position: relative
to ensure that the final presentation takes up the full page. Without the associated JavaScript, the CSS on the div
will make no difference, and images will fade in together as one after a one-second delay.
Adding Web Animation
With the basic presentation in place, we can add JavaScript. The first thing we must do is turn off the default animation; we do this by removing the shuffle
class:
var reveal = document.querySelector(".reveal");
reveal.classList.remove("reveal");
var revealedImages = reveal.querySelectorAll("img"),
i = 1;
The images will be randomly distributed and angled, so I’ll make a function that covers randomness between two values:
function getRandom(min, max) {
return Math.random() * (max - min) + min;
}
With all the images inside the <div>
read into an array, I can loop through each one:
Array.prototype.forEach.call(revealedImages, function(photo) {
setTimeout(function(){
photo.style.position = "absolute";
photo.style.width = getRandom(33,45)+"%";
photo.style.left = getRandom(-5,65)+"%";
photo.style.top = getRandom(-6,60)+"vh";
photo.classList.add("expose");
var animate = photo.animate([
{ opacity: '0', transform: 'rotate('+getRandom(-12,12)+'deg) scale(1.2)',
boxShadow: '0 0 12px 12px rgba(0,0,0,.3)' },
{ opacity: '1', transform: 'rotate('+getRandom(-8,8)+'deg)',
boxShadow: '0 0 6px 6px rgba(0,0,0,.3)' }
], {
duration: 2000,
fill: 'forwards'
});
}, 1800*i)
i++;
})
Each photo
in turn is:
- provided with
absolute
positioning, so we can move it anywhere in relation to its containing element. - given a random
width
as a percentage of its container, between 33 and 45%. - given a random
left
as a percentage, between-5
and65
, meaning that images may go slightly off the screen to the left or right - defined in its vertical position by a
top
measured invh
units. Again, the range of numbers used mean that the photo may appear slightly outside the viewport. - provided with a class of
expose
, that defines a frame for the image. The class is added to the page’s stylesheet so that the script can draw from it:
.expose {
border: 1.4rem solid #eee;
}
The random animated nature of the scattered photos makes movement with the Web Animation API an obvious use, via an animate
variable:
- the initial
opacity
of the photo is set to0
, and provided with a random initial rotation and ascale
of1.2
. A spreadboxShadow
is also applied (note the camelCasing and lack of hyphen in the property when it is used in JavaScript). - the photo is animated to full opacity, a (likely) different angle, and a tighter
box-shadow
. By not defining it in the second keyframe,scale
is automatically set to1
. - each animation takes 2 seconds, and is delayed by the value of the incrementor
i
multiplied by 1000 milliseconds.
Conclusion & Improvements
Coupled with a good Web Animation API polyfill for browsers that don’t support the specification, the result works very well. However, there’s plenty of room for improvement:
- The random
left
andtop
ranges are simply “guesstimates”: it would be nice to work them out from the maximumwidth
andtop
value of the photos, coupled with their aspect ratios. - The images automatically stack on each other in the order they appear on the page. It might be useful to randomly shuffle the photos so they appear in a different order each time.
- The layering effect obscures images that have been previously placed; it would be helpful if the elements could be dragged and re-ordered by the user.
I’ll be covering those possibilities in future articles, in association with other demos.
Photographs by Liam Wong, used with permission.
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/yJNvaa