sylvain durand

Overlay image in pure CSS

There is no native solution within browsers to display, on click, a full screen image. Several Javascript libraries have come to fill this gap: Lightbox (which was a precursor, to the point of giving its name to the concept), Fancybox, PhotoSwipe…

These solutions are sometimes heavy, whereas if you are only looking for a simple behavior, a few lines of CSS are enough, and no Javascript code is required.

Principle

:target selector

We will use the CSS selector :target, which allows to apply a style to an element when its identifier (id="") is the one of the anchor (#) in the page URL. To take an example:

<a href="#myid">Click to color in red!</a>
<div id="myid">Hello World!</div>

<style>
div:target {
  color: red;
}
</style>

Note that this selector actually allows you to add a lot of interactive elements to a page without Javascript, such as showing and hiding an element or a navigation bar.

Compatibility

According to developer.mozilla.org and caniuse.com, the :target selector is supported by all browsers released since 2008, and especially since Internet Explorer 9.

HTML

For each image, the HTML markup will be as simple as possible:

<!-- The link that, when clicked, will display the image in full screen -->
<a href="#img-id">
  <img src="image-thumbnail.png" alt="Thumbnail">
</a>

<!-- The full screen image, hidden by default  -->
<a href="#_" class="overlay" id="img-id">
  <img src="image-fullscreen.png" alt="Fullscreen">
</a>

The first line, customizable at will, will display the image in full screen thanks to the link to #img-id. The second, hidden by default, contains the corresponding identifier.

If several images are present on the page, it will obviously be necessary to give them a unique identifier for each one, and to match the link.

The link to #_ has no particular meaning, and could have been replaced by #anything. It simply aims to cause #img-id to lose the status :target and therefore to close the full screen when clicking.

CSS

Display

The overlay is nothing more than a div with a fixed position, located at the top left and covering the entire page. We add a flex property to it to place the image in the center of it:


.overlay {
  /* Display over the entire page */
  position: fixed;
  z-index: 99;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0,0,0,0.9);

  /* Horizontal and vertical centering of the image */
  display: flex;
  align-items: center;
  text-align: center;

  /* We hide all this by default */
  visibility: hidden;
}

.overlay img{
  /* Maximum image size */
  max-width: 90%;
  max-height: 90%;

  /* We keep the ratio of the image */
  width: auto;
  height: auto;
}

Activation on click

As we have seen previously, we now have to add a visibility: visible with the selector :target to display all this when you click on the trigger link.

.overlay:target {
  visibility: visible;
  outline: none;
  cursor: default;
}

We add an outline: none to avoid the border that is displayed, by default, on several browsers. In addition, cursor: default, optional, avoids having a “hand” in place of the cursor on the entire page.

Animation

The Javascript libraries mentioned above allowed to have a nice fade effect when opening. Never mind: CSS allows almost any kind of madness in terms of animation.

We’re going to stay sober here, with a slight bland effect, with a very small zoom effect on the image.

.overlay {
  opacity: 0;
  transition: opacity .3s;
}

.overlay img {
  transform: scale(0.95);
  transition: transform .3s;
}

.overlay:target img {
    transform: scale(1);
}

Full code:

Finally, our CSS code became:


.overlay {
  position: fixed;
  z-index: 99;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0,0,0,0.9);
  display: flex;
  align-items: center;
  text-align: center;
  visibility: hidden;
  opacity: 0;
  transition: opacity .3s;
}

.overlay img{
  max-width: 90%;
  max-height: 90%;
  width: auto;
  height: auto;
  transform: scale(0.95);
  transition: transform .3s;
}

.overlay:target {
  visibility: visible;
  outline: none;
  cursor: default;
}

.overlay:target img {
    transform: scale(1);
}

Bonus: shortcode for Hugo

With the static website generator Hugo, you can easily automate the process with a shortcode. To do so, we create a img.html file in layouts/shortcodes/:

<a href="#{{ anchorize (.Get "src") }}">
  <img src="{{.Get "src" }}" alt="{{.Get "alt" }}" />
</a>
<a href="#_" class="overlay" id="{{ anchorize (.Get "src") }}">
  <img src="{{.Get "src" }}" alt="{{.Get "alt" }}">
</a>
{{ .Inner }}

Then, you just have to add, in your articles:

{{< img src="image.jpg" alt="Description" />}}