Animated Grainy Texture

The DayTrip website uses a neat effect on its page header that distorts the background image with an animated, grainy texture. The effect is subtle but creates a dusty, retro vibe.

The effect is very subtle. You can see the the difference where the effect is in place on the right and disabled on the left:

No effect (left) vs. Grainy effect (right)

We can create the same rustic effect with a single image and a little bit of CSS.

Step 1: Setting Things Up

First, let's set up the our page header. We're going to use a common pattern where a background image takes up the entire space.

.page-header {
  height: 100vh;
  background-image: url("/path/to/image.jpg");
}

Here's an example to get us started:

See the Pen RpLKdx by Geoff Graham (@geoffgraham) on CodePen.

Step 2: Selecting a Texture

Next, we need an image with a grainy texture to it. You can create this yourself. Subtle Patterns also has a number of nice options, including this one that we'll use for our demo. Note that the image does not need to be huge. Something in the neighborhood of 400px square will do the trick.

The idea is that we will overlay the grainy texture on top of the .page-header. We can use the :after pseudo-element on .page-header so there is no need to create another element.

.page-header {
  height: 100vh;
  background-image: url("/path/to/image.jpg");
}

.page-header:after {
  /* content is required when using :after */
  content: "";
  /* The grainy image */
  background-image: url("/path/to/grainy/image.jpg");
  /* Specify a height and width above and beyond the page header for movement */
  height: 300%;
  width: 300%;
  /* We're using opacity in place of a transparent image */
  opacity: 0.3;
  /* We'll need this when the animation kicks in to hold the position of the texture */
  position: fixed;
}

Note that we placed a height and width on the pseudo-element as well as a top and left so that it actually exceeds the boundary of the page header and is centered to it. We want to do this so that the grainy texture layer has room to move around without exposing the page header layer underneath. This means are layers are arranged more like this:

The top layer now exceeds the bounds of the page header

Now we have a nice big page header with a grainy image on top:

See the Pen evGvKg by Geoff Graham (@geoffgraham) on CodePen.

Step 3: Animating the Grainy Layer

The last thing we need to do is animate the grainy layer. This is the effect that we're going after and gives the page header that retro, analog appeal.

The DayTrip site uses the following to define the animation keyframes:

@keyframes grain {
  0%, 100% { transform:translate(0, 0) }
  10% { transform:translate(-5%, -10%) }
  20% { transform:translate(-15%, 5%) }
  30% { transform:translate(7%, -25%) }
  40% { transform:translate(-5%, 25%) }
  50% { transform:translate(-15%, 10%) }
  60% { transform:translate(15%, 0%) }
  70% { transform:translate(0%, 15%) }
  80% { transform:translate(3%, 35%) }
  90% { transform:translate(-10%, 10%) }
}

It's sort of tough to visualize what that code means, but it's basically moving the top grainy layer around in a zig-zag pattern. Here's an illustration of what that looks like at a smaller scale:

Now all we have to do is apply the keyframes to .page-header:after to see it take effect. We'll set the animation to play for 8 seconds and loop infinitely:

.page-header:after {
  /* content is required when using :after */
  content: "";
  /* The animation */
  animation: grain 8s steps(10) infinite;
  /* The grainy image */
  background-image: url("/path/to/grainy/image.jpg");
  /* Specify a height and width above and beyond the page header for movement */
  height: 300%;
  width: 300%;
  /* We're using opacity in place of a transparent image */
  opacity: 0.3;
  /* We'll need this when the animation kicks in to hold the position of the texture */
  position: fixed;
}

Putting it All Together

Here's the full snippet with all the pieces in place. Note that we are assuming the use of Autoprefixer for all vendor prefixing.

.page-header {
  height: 100vh;
  background-image: url("/path/to/image.jpg");
}

.page-header:after {
  animation: grain 8s steps(10) infinite;
  background-image: url("/path/to/grainy/image.jpg");
  content: "";
  height: 300%;
  left: -50%;
  opacity: 0.3;
  position: fixed;
  top: -100%;
  width: 300%;
}

@keyframes grain {
  0%, 100% { transform:translate(0, 0) }
  10% { transform:translate(-5%, -10%) }
  20% { transform:translate(-15%, 5%) }
  30% { transform:translate(7%, -25%) }
  40% { transform:translate(-5%, 25%) }
  50% { transform:translate(-15%, 10%) }
  60% { transform:translate(15%, 0%) }
  70% { transform:translate(0%, 15%) }
  80% { transform:translate(3%, 35%) }
  90% { transform:translate(-10%, 10%) }
}

See the Pen Animated Grainy Effect by Geoff Graham (@geoffgraham) on CodePen.

Comments

  1. User Avatar
    Alex Zaworski
    Permalink to comment#

    The effect is very subtle.

    Ha, no kiddin’. I don’t think I’d have ever noticed if it weren’t pointed out— I quite like it now that I’ve seen it though.

  2. User Avatar
    goose
    Permalink to comment#

    Now that I understand how it works, I can see the grain moving and changing directions. Trippy CSS trick.

  3. User Avatar
    fwolf
    Permalink to comment#

    Note: Link to Subtle Patterns is broken.
    If the toptal.com site looks like too much of ad whoring, you might want to link to the github repo instead ;)

    cu, w0lf.

  4. User Avatar
    Archie
    Permalink to comment#

    Well, I have been using gifs. Only did it once and it never made it to the public.

    Here is an example (not my code): https://codepen.io/leemark/pen/dJxHp

    Are there any limitations to using gifs?

  5. User Avatar
    Dknight
    Permalink to comment#

    Really simple and tricky effect! Like it
    Cheers!

  6. User Avatar
    James
    Permalink to comment#

    If you remove the opacity from the overlay and use ‘mix-blend-mode: color-dodge;’ then you get a cleaner finish.

Submit a Comment

Posting Code

You may write comments in Markdown. This makes code easy to post, as you can write inline code like `<div>this</div>` or multiline blocks of code in triple backtick fences (```) with double new lines before and after.

Code of Conduct

Absolutely anyone is welcome to submit a comment here. But not all comments will be posted. Think of it like writing a letter to the editor. All submitted comments will be read, but not all published. Published comments will be on-topic, helpful, and further the discussion or debate.

Want to tell us something privately?

Feel free to use our contact form. That's a great place to let us know about typos or anything off-topic.

icon-closeicon-emailicon-linkicon-logo-staricon-menuicon-nav-guideicon-searchicon-staricon-tag