DEV Community


Posted on

Animating text over images in JS


I've been building a personal blog site for my writing and photography, and it's been a great excuse to experiment with CSS that I don't always get a chance to use.

In this post, I'll walk through how to animate text over a background image. In my portfolio, I use it to animate over image previews of posts. It'll end up looking something like this:

animation example


My solution uses React and Emotion, but the principal of how I animate over my image should be viable for any other front-end framework.

My approach was to create a container for the background image, and then lay a container on top of the background image. The top container is translucent until it is hovered over, and then it and the text it contains become opaque.

The html structure (here, written in jsx) looks like this:

<BackgroundImg alt={alt_text}>
    <AnimatedParagraph>{paragraph_text </AnimatedParagraph>

Using the @emotion/styled library, I made 3 CSS-in-JS styled components to represent these 3 blocks. Code with in-line comments below.

Note that BackgroundImage here is a wrapper component from Gatsby.js that does some nice image-load optimization functions in the background, but for your purposes you could use a div.

// Styling and Animation for Desktop
const BackgroundImg = styled(BackgroundImage)`
  width: 33vw;
  height: 33vw;
  margin: 2vw 2vw 2vw 2vw;

const Hover = styled.div`
  height: 100%;
  width: 100%;

  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;

  /* The component is not opaque, but opacity transitions out for 300ms */
  background-color: #efece4;
  opacity: 0;
  transition: opacity 300ms ease-in-out;

  /* When the user hovers over the component, it becomes opaque over 300ms */
  &:hover {
    opacity: 0.95;
    transition: opacity 300ms ease-in-out;

  /* All children (animated text) move to default position when component is hovered over */
  &:hover > * {
    transform: translate3d(0, 0, 0);

const AnimatedTitle = styled.h2`
  /* Transform to 50px down on load, but user doesn't see this because div this text is in is translucent  */
  transform: translate3d(0, 50px, 0);
  transition: transform 300ms ease;
  text-align: center;
  margin-bottom: 10px;
const AnimatedParagraph = styled.p`
  transform: translate3d(0, 50px, 0);
  transition: transform 300ms ease;
  text-align: center;
  margin-bottom: 0;
  font-size: 12px;
  font-style: italic;


This of course only scratches the surface of the transformations and animations CSS is capable of. Highly recommend the MDN spec to anyone who wants a more thorough overview of CSS transforms and transitions. I hope this post has been helpful for anyone trying to solve a similar problem.

Discussion (0)