How to Create Pure CSS onClick Image Zoom Effect

CSS doesn’t have a pseudoclass for targeting click events, and this constitutes one of the biggest pain points of front-end developers. The closest pseudo-class is :active which styles an element for the period of time a user presses their mouse over it.

The Definitive Guide to CSS Pseudo-Classes

The Definitive Guide to CSS Pseudo-Classes

Whether you are a novice or an experienced CSS developer, you probably have heard of pseudo-classes. The most…Read more

This effect is however short-lived: once the user releases the mouse, :active doesn’t work any more. We need to find some other way to emulate the click event in CSS.

This post has been written in response to a reader’s request, and it’s going to explain how to target the click event with pure CSS in a specific use case, image zoom.

You can see the final result below — a CSS-only solution for image zoom on click.

When to Use the CSS-Only Solution

Before I proceed, I do want to say, that for image zoom I recommend the CSS-only method (which changes the dimensions of the image), only when you want a single or a group of few images to have the zoom feature.

For a proper gallery, JavaScript provides more flexibility and efficiency.

Front-End Techniques We’ll Use

Now that you’ve been cautioned, let’s quickly look over the 3 key techniques we’ll be using:

  1. The <map> HTML tag that allows browsers to create linkable areas over an image. Read more on the <map> element in my earlier post.
  2. The usemap attribute of the <img> tag, that hooks up the image to the image map.
  3. The :target CSS pseudo-class that represents an element that has been targeted using its ID selector.
1. Create the HTML Base

First, let’s create the HTML base. In the code below, we add an image to be zoomed and expanded & close button icons for zooming in and out.

<img id="img1" class="img" src="http://bit.ly/2acrH5J" />
<a href="#" class="close"></a>
<img class="expand" src="Expand-icon.png" />

It’s important to have an ID on the image to be zoomed, and the Close button needs to be a link that has the href="#" attribute, I’ll explain why later in the post.

2. Add the CSS

Initially, the Close icon shouldn’t be displayed. The position, margin-, left, and bottom properties place the Expand and Close icons where we want them to be — at the top-right corner of the image.

The pointer-events: none; rule allows mouse events to pass through the Expand icon and reach the image.

.img {
  height: 150px;
  width: 200px;
}
.close {
  background-image: url("Close-icon.png");
  background-repeat: no-repeat;
  bottom: 418px;
  display: none;
  height: 32px;
  left: 462px;
  margin-top: -32px;
  position: relative;
  width: 32px;
}
.expand {
  bottom: 125px;
  margin-left: -32px;
  margin-right: 16px;
  pointer-events: none;
  position: relative;
}
Image with Expand Button
Initial state with visible Expand and hidden Close icons
3. Add the Image Map

On the image map, the clickable area should be at the top-right corner of the image right below the Expand icon, and about its size. Place the <map> element before the first <img> tag in the HTML. We’ll bind the image to the map in the next step.

<map name="m1">
  <area shape="rect" coords="170 5 195 30" href="#img1">
</map>

In the code block above, the <area> tag defines the shape, size, and URI of a linkable area inside an image map. For a rectangular shape, the shape attribute takes the rect value, and the four values of the coords attribute represent the distance in pixels between:

  1. the left edge of the image & the left edge of the link area
  2. the top edge of the image & the top edge of the link area
  3. the left edge of the image & the right edge of the link area
  4. the top edge of the image & the bottom edge of the link area

The value of the href attribute has to be the hash identifier of the image (this is why the image should have an id).

4. Bind the image to the Image Map

Add the usemap attribute to the image so as to bind it to the image map. Its value needs to be the hash representation of the name attribute of the <map> tag we added in Step 3.

<img id="img1" class="img" usemap="#m1"
    src="http://bit.ly/2acrH5J" />

The clickable area of the image map now lies behind the Expand button. When the user clicks the Expand button, it’s the clickable area that is clicked in reality — remember that we made the Expand button “passable” with the pointer-events: none; rule in Step 2.

This way the user targets the image itself by clicking it, and after the click the URI gets suffixed with the "#img1" fragment identifier.

5. Style the :target Pseudo-Class

Until the "#img1" fragment identifier is at the end of URI, the targetted image can be styled with the :target pseudo-class

The dimensions of the targeted image increase, the Close button gets shown, and the Expand button gets hidden.

.img:target {
    height: 450px;
    width: 500px;
}
.img:target+.close {
    display: block;
}
.img:target+.close+.expand {
    display: none;
}
Zoomed Image with Visible Close Button
Zoomed Image with Visible Close button
How the Close Button Works

As the Close button was added as a background image (Step 2), and is actually an <a> tag with the href=# attribute (Step 1), when it’s clicked, it removes the fragment identifier from the end of the URI. Therefore it also removes the :target pseudo-class from the image, and the image goes back to its previous size.

Now the CSS-only zoom-on-click effect is done, check out the demo below, or read a little bit more on the theory behind image maps in the next section.

Background Info: Why <map> and not <a>?

By now, you certainly understand that the most important thing for this CSS-only solution to work is to target the image using the href="#imgid" attribute, which could also be done using the <a> tag instead of the image map.

This may be true, however when it comes to images, using the <map> element is more appropriate. It’s even more important that when you want the zoom to happen on clicking on a larger area on the image rather than just on the Expand icon, <map> gives you an easy solution.

<map name="m1"><area shape="default" href="#img1"></map>

The default value for shape attribute creates a rectangular linkable area that covers the whole image. If you were to use <a> instead, you would have to code it to cover the image, and you may also have to use a wrapper element for the same purpose.

To also speak about the caveats of this solution, the pointer-events CSS property (we used in Step 2) is supported by Internet Explorer only from version 11.

To support IE browsers before that, you may want to either use <a> instead of <map>, or have the image zoomed on by clicking anywhere on it (in this case there’ll be no need for the Expand icon).

FacebookTwitterInstagramPinterestLinkedInGoogle+YoutubeRedditDribbbleBehanceGithubCodePenEmail