Responsive featured images

I’ve followed Laura Kalbag’s post to process responsive images inside posts. Each image in a post is resized to 4 different dimensions and placed inside resources/_gen/images/…/postFolder. The shortcode img.html then outputs the proper imgsrc html in the post. Very nice!

I’d like to use the same processed images to display as featured images.

This article explains how to display a featured image. That works fine.

But the solution recommended by @bep creates a new set of resized images.

Is it possible to apply the shortcode method to the featured image for each post so I don’t have to deal with a duplication of processed images?

Although Laura’s code has been a valuable start point, there’s been some significant changes since and it would now make more sense to use render hooks along with a partial.

You first need a partial for your thumbnail generation logic and markup. Then this can be both included in a render hook for images, and a partial that you can use to make the individual articles / pages.

I’ve created a similar solution to what you seek, that you could build on:


I’m sorry, I’m having a really hard time understanding the advantages of render hooks over shortcodes. Is it just that you avoid having multiple copies of the resized images? Could you please explain the pros and cons further?

Here’s a shortcode I wrote for my work-in-progress Hugo theme, also vaguely based off of Laura’s code. I wrote different shortcodes for different image sizes (probably could be rewritten as one shortcode with conditionals), this is the simplest one which is always the full width of the screen. You call it by writing e.g. {{<imgfull src="schuylkill.jpg" alt="The Schuylkill River in winter.">}}

{{/* Avoid using this shortcode on images less than 3840 pixels wide */ -}}

{{/* get file that matches the filename as specified as src="" in shortcode */}}
{{ $src := .Page.Resources.GetMatch (printf "*%s*" (.Get "src")) -}}

{{ $imgSrc := "" -}}
{{ $imgSrcSet := slice -}}

{{ $widths := site.Params.screenWidths -}}
{{ $fallback := site.Params.fallbackSize | default 1440 -}}

{{ range $widths -}}
	{{ if ge $src.Width . -}}
		{{ $srcUrl := (printf "%dx" . | $src.Resize).RelPermalink -}}
		{{ if and (eq $imgSrc "") (ge . $fallback) }}{{ $imgSrc = $srcUrl }}{{ end -}}
		{{ $imgSrcSet = $imgSrcSet | append (printf "%s %dw" $srcUrl .) -}}
	{{ end -}}
{{ end -}}
{{ if eq $imgSrc "" }}{{ $imgSrc = $src.RelPermalink }}{{ end -}}
{{ $imgSrcSet = (delimit $imgSrcSet ",\n\t") -}}

	{{ with .Get "sizes" }}sizes='{{.}}'{{ else -}}
	{{ end -}}
	srcset="{{ $imgSrcSet }}"
	src={{ $imgSrc }}
	width={{ $src.Width }}
	height={{ $src.Height }}
	{{ with .Get "alt" -}}
	{{ end -}}

That produces HTML like this:

	srcset="/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_576x0_resize_q75_box.jpg 576w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_720x0_resize_q75_box.jpg 720w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_900x0_resize_q75_box.jpg 900w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_1080x0_resize_q75_box.jpg 1080w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_1280x0_resize_q75_box.jpg 1280w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_1366x0_resize_q75_box.jpg 1366w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_1440x0_resize_q75_box.jpg 1440w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_1600x0_resize_q75_box.jpg 1600w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_1800x0_resize_q75_box.jpg 1800w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_1920x0_resize_q75_box.jpg 1920w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_2160x0_resize_q75_box.jpg 2160w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_2304x0_resize_q75_box.jpg 2304w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_2560x0_resize_q75_box.jpg 2560w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_2880x0_resize_q75_box.jpg 2880w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_3200x0_resize_q75_box.jpg 3200w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_3384x0_resize_q75_box.jpg 3384w,
	/blog/2020/10/pictures/schuylkill_hu1966b96707887b7b85192359bda88cdb_1900414_3840x0_resize_q75_box.jpg 3840w"
	alt="The Schuylkill River in winter."

With Markdown Image Render Hooks you can control the output of plain markdown syntax images, and at the same time your content files will be 100% Markdown and thus portable to any editor.

Also if you use Leaf Page Bundles then you will also be able to have image previews of the Markdown syntax images in any editor.

Same goes for the other formats of Markdown Render Hooks, for example you can write a simple Markdown syntax link and output it wrapped in whatever HTML tag you may need.

Hugo shortcodes work the same as Markdown Render Hooks in outputting whatever HTML may be needed, but one will not have the above benefits.

Hugo shortcodes are not recognised by other editors, therefore you will not be able to have image previews out-of-the-box.

Also content files with Hugo shortcodes are less portable since they no longer use only Markdown syntax.

These days I use Markdown Render Hooks for images and links.
I am only using Hugo Shortcodes for pages that require complex layouts.

1 Like

With Render-Hooks it works automatic for all images!

ex: my image hook template

The rendered image sizes are defined in the config file

Thanks for the help everyone, I’ve got an initial render hook for images working! I just replaced printf "*%s*" (.Get "src") with .Destination when getting the image url, and .Get "alt" with .Text to get the alt text, and that’s about all I had to do to translate my shortcode into a render hook.

Does anyone know if it’s possible to get rid of the <p> tags around images, using render hooks? I really thought this would be possible with the extra control from render hooks, but maybe I have to stick with shortcodes if I hate the extra <p> tags.

The short answer: no

The long answer:

1 Like

Thank you for linking the explanation. You’ve saved me a lot of time, because the next thing I was going to try to do was include a figure + figcaption in my render hook! Back to shortcodes for that, I guess.

Incidentally, attempting to target a lonely image wrapped in <p> tags using e.g. p img:only-child in CSS will not work, because text in that paragraph doesn’t count as a separate element, therefore an image can be surrounded by text in a paragraph but still be an “only-child”.

I made a similar mistake with :first-child and :last-child before, trying to target images at the beginning and end of paragraphs, and it doesn’t work. Just a reminder to my future self!