# Medium-like lazy loading of images

**URL:** https://discourse.gohugo.io/t/medium-like-lazy-loading-of-images/16016
**Category:** tips & tricks
**Created:** [December 27, 2018, 4:00pm UTC](https://discourse.gohugo.io/t/medium-like-lazy-loading-of-images/16016 "2018-12-27T16:00:26Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![Igor\_Kulman](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/igor_kulman/32/901_2.png) [@Igor\_Kulman](https://discourse.gohugo.io/u/Igor_Kulman)
#### Post date: [December 27, 2018, 4:00pm UTC](https://discourse.gohugo.io/t/medium-like-lazy-loading-of-images/16016/1 "2018-12-27T16:00:26Z")

</div>

I was looking for a good way to lazy load image son my website and stumbled upon [https://www.botreetechnologies.com/blog/page-load-optimization-by-progressive-image-loading-like-medium](https://www.botreetechnologies.com/blog/page-load-optimization-by-progressive-image-loading-like-medium). 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`

```auto
{{ $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>
</div>
</div>

```

that can be called using

```auto
{{% 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

```css
.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;
}

.image_placeholder{  
  display: block;
}

```

```auto
<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 () {
      smallImgElement.addClass('loaded');
    };

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

  })

}
</script>

```

You can see it in action at [https://blog.kulman.sk/](https://blog.kulman.sk/), especially in the Projects section.

---

<div class="post-metadata">

### Author: ![brunoamaral](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/brunoamaral/32/21144_2.png) [@brunoamaral](https://discourse.gohugo.io/u/brunoamaral)
#### Post date: [December 27, 2018, 5:57pm UTC](https://discourse.gohugo.io/t/medium-like-lazy-loading-of-images/16016/2 "2018-12-27T17:57:17Z")

</div>

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

---

<div class="post-metadata">

### Author: ![pritamps](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/pritamps/32/7786_2.png) [@pritamps](https://discourse.gohugo.io/u/pritamps)
#### Post date: [January 25, 2019, 7:29am UTC](https://discourse.gohugo.io/t/medium-like-lazy-loading-of-images/16016/3 "2019-01-25T07:29:23Z")

</div>

Thanks for this!! I modified it a bit to use only vanilla JS in case anyone’s interested.

```auto
window.onload = function() {

  var placeholder = document.querySelectorAll('.progressive_figure');

  placeholder.forEach(element => {
    var smallImage = element.getElementsByClassName('img-small')[0];

    // Load placeholder image
    var img = new Image();
    img.src = smallImage.getAttribute('src')
    img.onload = function () {
      smallImage.classList.add('loaded')
    }
    
    // Load large image
    var largeImage = new Image();
    largeImage.srcset = element.getAttribute('data-imgset');
    largeImage.src = element.getAttribute('data-src');
    largeImage.classList.add('lozad')
    largeImage.onload = function () {
      largeImage.classList.add('loaded');
      smallImage.replaceWith(largeImage);
    }
})};

```

---

<div class="post-metadata">

### Author: ![Jonathan\_Griffin](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/jonathan_griffin/32/8355_2.png) [@Jonathan\_Griffin](https://discourse.gohugo.io/u/Jonathan_Griffin)
#### Post date: [January 25, 2019, 9:27am UTC](https://discourse.gohugo.io/t/medium-like-lazy-loading-of-images/16016/4 "2019-01-25T09:27:04Z")

</div>

I haven’t really read the detail of this thread, but this link is very important: [https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/](https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/)

It provides guidance on how to do lazy loading images so they can be seen by Google.

---

<div class="post-metadata">

### Author: ![pritamps](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/pritamps/32/7786_2.png) [@pritamps](https://discourse.gohugo.io/u/pritamps)
#### Post date: [January 25, 2019, 9:32am UTC](https://discourse.gohugo.io/t/medium-like-lazy-loading-of-images/16016/5 "2019-01-25T09:32:01Z")

</div>

From what I understand (I’m only getting started with JS), the technique in the OP of this thread is about only the progressive-loading part of lazy loading.

For lazy loading (loading image only when scrolled to), you’ll have to use the Intersection Observer etc, as described in the Google link. [This library](https://github.com/ApoorvSaxena/lozad.js) does it quite well if you’re interested.

---

<div class="post-metadata">

### Author: ![Igor\_Kulman](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/igor_kulman/32/901_2.png) [@Igor\_Kulman](https://discourse.gohugo.io/u/Igor_Kulman)
#### Post date: [March 9, 2019, 6:01pm UTC](https://discourse.gohugo.io/t/medium-like-lazy-loading-of-images/16016/6 "2019-03-09T18:01:34Z")

</div>

One new trick. Instead of linking the 48px placeholder image, you can just generate a much smaller image, say 2px and embed it directly to the HTML as base64:

{{ $image := (.Page.Resources.GetMatch (index .Params 0)) }}  
{{ $placeholder := $image.Resize “2x q20” }}

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

---

<div class="post-metadata">

### Author: ![ju52](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/ju52/32/6749_2.png) [@ju52](https://discourse.gohugo.io/u/ju52)
#### Post date: [March 10, 2019, 8:50am UTC](https://discourse.gohugo.io/t/medium-like-lazy-loading-of-images/16016/7 "2019-03-10T08:50:56Z")

</div>

my 2 cents

to avoid the **content jumping** around, put the image size in the html content, like this

`<img class="imageclass" src="{{ $image.RelPermalink }}" width={{ $image.Width }} height={{ $image.Height }} />`

With the right CSS-class you can define the needed borders etc.

@pritamps suggests a way to load images during scrolling - different beast
