In this blog post we will look into how we can add a Zoom-In effect for better visibility.

We will be using Markdown Render Hooks from Hugo with HTML & CSS, implementing a non-javascript solution.

About Markdown Render Hooks

Hugo offers really handy Markdown Render Hooks. These allow custom templates to override markdown rendering functionality.

We will be using render-image hook to process out the images in the post as per our needs. The render-image hook stays in the location shown below.

* (site root)
โ”œโ”€โ”€ layouts
โ”‚   โ””โ”€โ”€ _default
โ”‚       โ””โ”€โ”€ _markup
โ”‚           โ””โ”€โ”€ render-image.html
โ””โ”€โ”€ themes

The code snippet </>

For adding a Zoom-in effect we will be using a combination of input and label field inside which we will place our image.

Basic Idea:

  • We have in input field of type checkbox.
  • We link the checkbox and label with an Unique Id generated for each image. In short we have a checkbox with a clickable label
  • Inside the label we have our image placed.
  • Whenever the user clicks on image, it activates the checkbox and its value is set as checked.
  • To make it look nicer, we hide the checkbox, using hidden attribute.
  • In CSS rules we add a transform property to image when the checkbox is checked.

Note: We are only enabling this on displays with width >=769px. Smaller displays target touch sceen devices such as phones, where image zooming in is not effective as width is quite less.

Contents of render-image.html

Put these into (.)/layouts/_default/_markup/render-image.html

<!-- Checks if page is part of section and page is not section itself -->
{{- if and (ne .Page.Kind "section") (.Page.Section ) }}
    <!-- Generate a unique id for each image -->
    {{- $random := (substr (md5 .Destination) 0 5) }}
    <input type="checkbox" id="zoomCheck-{{$random}}" hidden>
    <label for="zoomCheck-{{$random}}">
        <img class="zoomCheck" loading="lazy" decoding="async" 
            src="{{ .Destination | safeURL }}" alt="{{ .Text }}" 
            {{ with.Title}} title="{{ . }}" {{ end }} />
{{- else }}
    <img loading="lazy" decoding="async" src="{{ .Destination | safeURL }}" 
        alt="{{ .Text }}" {{ with .Title}} title="{{ . }}" {{ end }} />
{{- end }}

Corresponding styling in css

Put these into (.)/layouts/<theme specific extend_head.html>

@media screen and (min-width: 769px) {
    /* .post-content is a class which will be present only on single pages 
        and not lists and section pages in Hugo */
    .post-content input[type="checkbox"]:checked ~ label > img {
        transform: scale(1.6);
        cursor: zoom-out;
        position: relative;
        z-index: 999;

    .post-content img.zoomCheck {
        transition: transform 0.15s ease;
        z-index: 999;
        cursor: zoom-in;

Sample Image with Zoom-In effect

Click on the below image to Zoom-In and Zoom-Out.
(Works with displays having width >=769px)