Medium-like lazy loading of images


I was looking for a good way to lazy load image son my website and stumbled upon This post describes how to do image lazy loading similar to what medium does

  • Show a div the same size as the resulting image (so the content does not “jump” after the image is loaded)
  • Load a very small low quality placeholder and blur it in the div
  • Load the final image

I made it into a reusable shortcode

{{ $image := (.Page.Resources.GetMatch  (index .Params 0)) }}
{{ $placeholder := $image.Resize "48x q20" }} 

<div class="image_placeholder" style="max-width: {{$image.Width}}px">
<div class="placeholder" data-large="{{ $image.Permalink }}">  
  <img src="{{ $placeholder.Permalink }}" class="img-small">
  <div style="padding-bottom: {{ div (mul $image.Height 100.0) $image.Width }}%;"></div>

that can be called using

{{% post-image "image.png" %}}

but only works with page bundle images to be able to use the Hugo image resizing functionality.

The JavaScript and CSS stay the nearly same as in the post, I just adjusted them for my theme

.placeholder {
  background-color: #f6f6f6;
  background-size: cover;
  background-repeat: no-repeat;
  position: relative;
  overflow: hidden;

.placeholder img {
  position: absolute;
  opacity: 0;
  top: 0;
  left: 0;
  width: 100%;
  transition: opacity 1s linear;

.img-small {
  filter: blur(50px);
  /* this is needed so Safari keeps sharp edges */
  transform: scale(1);

.placeholder img.loaded {
  opacity: 1;

  display: block;
<script type="text/javascript">
window.onload = function() {

  var placeholder = $('.placeholder');

  placeholder.each( function(index) {
    // 1: load small image and show it
    var smallImgElement = $(this).find('.img-small');
    var img = new Image();
    img.src = smallImgElement.attr('src');
    img.onload = function () {

    // 2: load large image
    var imgLarge = new Image();
    imgLarge.src = $(this).data('large');
    imgLarge.onload = function () {



You can see it in action at, especially in the Projects section.


This is pretty cool. And you can also use the hasShortcode function to only load the JS in page where it is being used. :slight_smile: