Zooming Background Images

Avatar of Dylan Winn-Brown
Dylan Winn-Brown on (Updated on )

The following is a guest post by Dylan Winn-Brown, who shows us a performant way to accomplish this design effect.

Whilst working on a client’s website recently, I was asked to replicate an effect like this.

Containers with background images which zoom within their container on hover, revealing more information.

This type of effect is notably used in portfolio-type situations where the design intends to show both visual and informational details.

There are many different possible methods

As I had never created an effect like this before, I began to take a look at different ways of doing this and came across a number of different methods.

One option was to use a jQuery Plugin. This one wasn’t quite the effect I was after, and certainly not very lightweight.

Another option was to position an <img> within the container and manipulate it with CSS. There could be some potential benefits here, like being able to set the source with srcset so that the image used is performance and device-appropriate.

In my situation, I wanted to manage the effect entirely in CSS, so I went for that.

Basic functionality

In order to achieve optimal performance, I decided to use the CSS transform property to handle the enlargement of the image. (CSS animations benefit from hardware acceleration and as a result appear smoother than other methods of animating.)

Rather than an <img>, I used an additional <div> inside the parent to act as the image. The structure being:

<div class="parent">
  <div class="child"></div>
</div>

First we specify the dimensions for the parent element. Then the child can fill the parent using width: 100% and height: 100%;, as well as set the background image, ensuring it scales to cover the area.

.parent {
  width: 400px; 
  height: 300px;
}

.child {
  width: 100%;
  height: 100%;
  background-color: black; /* fallback color */
  background-image: url("images/city.jpg");
  background-position: center;
  background-size: cover;
}

We then add hover effects to our parent element which will affect our child element. A focus style is good for accessibility as well:

.parent:hover .child,
.parent:focus .child {
  transform: scale(1.2);
}

You may want to use a tool for adding prefixes for the best possible browser support.

To finish up the basic effect, we can add some transitions to our child element’s normal state:

transition: all .5s;

If you want to add a color overlay, you can make use of pseudo elements like ::before:

.child::before {
  content: "";
  display: none;
  height: 100%;
  width: 100%;
  position: absolute;
  top: 0;
  left: 0;
  background-color: rgba(52, 73, 94, 0.75);
}

.parent:hover .child:before,
.parent:focus .child:before {
  display: block;
}

Now when we hover on the parent element, the child element should show a color overlay!

Finally, we’ll cover how to add some text to show on our overlay. We can add an element to our current child element like so:

<div class="parent">
   <div class="child">
      <span>Hello</span>
   </div>
</div>

We can give our <span> some style:

span {
  color: white; /* Good thing we set a fallback color! */
  font-family: sans-serif;
  padding: 25%;
  position: absolute;
}

and we can make it visible only when we hover on the .parent:

.parent:hover span,
.parent:focus span {
  display: block;
}

Live Demo

See the Pen Image zoom on hover – portfolio websites by Dylan (@dwinnbrown) on CodePen.

Mobile Support

If the containers are links and the hover states don’t reveal any essential information, you might just leave it alone.

If the hover states are important, in order for this to work on touch screens, we can use empty onclick="" handlers on our .parent containers. Unfortunately I couldn’t come across another way of doing this but if any of you do, let me know in the comments!