A quick trick to create animated silhouettes in CSS
Tags: css, webdev
Published: 2023-10-06 11:00:00

I want to show you a shortcut to fashion an animated scene with silhouetted figures with very little CSS. It does not requires handcrafting an image in CSS, making a drawing in SVG, or using any JavaScript. File it under *creative* and maybe *frivolous*!

You can make something like this kitsch Halloween scene..

{% codepen https://codepen.io/robjoeol/pen/QWzZWzr %}

The silhouettes in the scene are styled with the same gradient.

You can think of it as a way to make a kind of animated collage! 

Let's unpack how this was made.

## The trick to make animated silhouettes

An interesting application of [CSS masks](https://developer.mozilla.org/en-US/docs/Web/CSS/mask) is that you can use an animated image, image formats such as [GIF](https://en.wikipedia.org/wiki/GIF) and [WebP](https://en.wikipedia.org/wiki/WebP), as the source of the mask. The trick is to choose an animated image with a transparent background that has distinct figures as the [`mask-image`](https://developer.mozilla.org/en-US/docs/Web/CSS/mask-image). When you give the element a solid [`background`](https://developer.mozilla.org/en-US/docs/Web/CSS/background) that you have applied the mask to, the element appears as an animation filled with your background style.

Let's make one now. There is a decent selection of these type of animated images on [Giphy](https://giphy.com/) in the *sticker* section. I will search for the term "wave".

![Searching for a "wave" sticker on Giphy. We choose the second image in the results to use in our codepen](https://www.roboleary.net/assets/img/blog/2023-10-06-animated-sillhoutes-css/giphy-search-wave.webp)

Then, we style a `div` as described. I apply `background-color:green` to turn the wave green!

```css
div{
  -webkit-mask-image: url("https://i.giphy.com/media/OzXfHi0efbEeA/giphy.webp");
  mask-image: url("https://i.giphy.com/media/OzXfHi0efbEeA/giphy.webp");
  
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  
  mask-repeat: no-repeat;
  
  
  /* need to set a background */
  background-color:green;
  
	/* need to set dimensions */
  width: 20rem;
  height: 20rem;
}
```

You can see the result in the codepen below.

{% codepen https://codepen.io/robatronbobby/pen/OJrapWx %}

You could use the shorthand [`mask` property](https://developer.mozilla.org/en-US/docs/Web/CSS/mask) to reduce the 3 mask-releated properties to a one-liner if you prefer!

## Browser interop issues

Chrome still requires prefixed properties for the effect to work. Chrome also expects `-webkit-mask-size` to be set, Firefox does not. [Interop 2023](https://web.dev/interop-2023/) is meant to be eradicating these interoperability issues.

## Which animated image formats should you use?

I would recommend favouring using more modern image formats over GIF that have much better compression. Some GIFs can be monsters! WebP and [AVIF](https://en.wikipedia.org/wiki/AVIF) support alpha transparency and animation, the mandatory ingredients, so they are the best options at the moment. WebP has total support across modern browsers and AVIF is making good headway.

## Accessibility

It is good practice to use the [`prefers-reduced-motion` media query](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) to reduce or disable animation for people with vestibular motion disorders. Something like this would suffice:

```css
/* Remove the animation to avoid vestibular motion triggers. */
@media (prefers-reduced-motion) {
  div{
    -webkit-mask-image: none;
  	mask-image: none;

    /* use a static background instead */
    background-image: url("img/static-green-wave.jpg");
  }
}
```