How to defer images?


In WordPress I defer images like this in the HTML file:

<img class="aligncenter" width="564" height="291" alt="Alt text" data-lazy-src="image.png" src="image.png">
<noscript><img src="image.png" alt="Alt text" width="564" height="291" class="aligncenter" /></noscript>

Then in my JavaScript file I defer them till page load:

function DeferLoadImages() {
  var imgDefer = document.getElementsByTagName('img');
  for (var i=0; i<imgDefer.length; i++) {
    if(imgDefer[i].getAttribute('data-lazy-src')) {

How can I do this in Hugo? It’s an important feature for me, but on the forum or in the documentation I couldn’t find how.

Edit: Just to clarify, I’m not asking how to do this HTML or JavaScript wise. I’m looking for a way so that Hugo converts the MarkDown image so that it has the required tags needed for defer loading (width, height, custom src like data-lazy-src, and the <noscript> version).

Hi Jura,

Thanks for the interesting concept. I am a newcomer Hugo, maybe it helps anyway.

Content Front Matter TOML

image = "img/post/real.png"

Template Code

<img class="aligncenter" width="564" height="291" alt="Alt text" data-lazy-src="{{ .Params.image }}" src="fast.png">

Or Markdown Inline? You had to create a shortcode

I think your best current bet is to create a shortcode.

Thanks Blenderman and Bep, a shortcode is the way to go; now my images are loaded after the browser has processed the HTML and CSS, which makes the website feel quicker. :slight_smile: It’s pretty amazing how versatile Hugo is once you know how to approach a problem/challenge.

What I did (perhaps it can help other beginners):

  1. Created an image.html shortcode:

    {{ .Get {{ .Get

    {{ if .Get “caption” }}
    {{ .Get “caption” }}
    {{ end }}

  2. Which is used in a MarkDown file as follows:


  3. I load my Javascript file on page load with this code in the footer just above </body> (code from

  4. In that Javascript file, the empty images are replaced with their actual content (i.e., swap data-src for src) (also from the feedthebot website):

    function DeferLoadImages() {
    var imgDefer = document.getElementsByTagName(‘img’);
    for (var i=0; i<imgDefer.length; i++) {
    if(imgDefer[i].getAttribute(‘data-src’)) {


By the way, how can I in the above shortcode include the .BaseURL variable? I get errors of Site is not a field of struct type *hugolib.ShortcodeWithPage for several versions of this variable ($.Site.BaseURL, .Site.BaseURL, .BaseURL).

See second line in the code below.

  <img data-src="{{ $.Site.BaseURL }} {{ .Get "src" }}"
    alt="{{ .Get "alt" }}" 
    width="{{ .Get "w" }}" height="{{ .Get "h" }}"/>

    <img src="{{ .Get "src" }}"
    alt="{{ .Get "alt" }}" 
    width="{{ .Get "w" }}" height="{{ .Get "h" }}"/>

The docs do mention that page variables are available in shortcodes, but there’s no mention of site variables.

In shortcodes Page isn’t the context, so you need this:

{{ $.Page.Site.BaseURL }} 

Thanks Bep.

If I may suggest a docs enhancement: is it perhaps an idea to create a tree-like overview of the different variables? In this case, for example, I would not have thought of $.Page.Site.BaseURL since with that Site is a subset of Page, which is counter-intuitive given how the variables normally work.

Just some feedback to try and help a little bit.

.Site is always a variable on Page (or Node), so this is “normal”. But document improvements are always welcome.

I write programming tutorials on my website, trying to convert the technical to the understandable. :wink: So I’m definitely interested in helping (and already thought about it). But unfortunately, I don’t know enough about Hugo yet to explain it well.

Hopefully someday. :slight_smile: