Append items to head based on data in body or partials used in body

I am trying to pre-load images via resource hints.
I am writing a complex partial which processes images and then if requested, appends the <link rel=“preload” data to scratch, and then the information needs to be ranged over in the head.

I am assuming this is not possible due to the fact that the body is compiled after the head.

Does anyone have any advice or a work around??

I am also trying to work out how to add page scoped CSS to the head from the body and partials using the same idea.

I have placed the following in the body and it works

{{ .Scratch.Add "head" (slice "test 1") }}
{{ .Scratch.Add "head" (slice "test 2" )}}
{{ .Scratch.Add "head" (slice "test 3" )}}
{{ $scratch := .Scratch.Get "head" }}

{{ range $scratch }}
{{ . }}
{{ end }}

The following in the head does not work

  {{ $scratch := .Scratch.Get "head" }}
  {{ range $scratch }}
  {{ . }}
  {{ end }}

Hi, I’m not a Hugo expert, and I’m not sure I understand your use case, but for the images part I’d try to put this logic into the render hook instead of a partial: Configure Markup | Hugo

HTH

I had a good look at render hooks and that could be a good option.

However I am trying to create a partial, and later a shortcode which accesses the partial.

The functionality which I am trying to reproduce is here Using rel=preload for responsive images | Bronco > Our Ideas

and has already been implemented here

Correct.

I don’t know how you are calling / running your partial, but you could do a pre-run in the head, so you can add whatever meta you need. Then run it again in the main section. partialCached might help if you structure your partials well.

Thanks for taking the time to read my problem.

I have had a look and I can’t find any information about pre-running a partial. Could you please elaborate on how this would work?

Basically in the body I specify an image, the partial in the body generates different image sizes, and if configured, and <link rel="preload" tag for the head, for above the fold images.

This is info on the preload Using rel=preload for responsive images | Bronco > Our Ideas

I have based much of my script off this plug in for next.js next/image | Next.js you will see the priority section.

This is the repository for my script GitHub - future-wd/hugo-image

The idea is:

<head>
{{ partial "foo.html" . }}
</head>
<!-- foo.html -->
{{/* img processing code here */}}
<link rel=...>

{{ .Scratch.Set ...}}

<body>
...
{{ partial "bar.html" }}
</body>
<!-- bar.html -->
{{ .Scratch.Get ... }}
<img ...>
  • So, you can put something in the head in a base template using blocks
  • You will, however, have the same “order problem” there.

The only, I think, workaround to that problem is to do all the image processing etc. before you need it.

One trick is to assign partials, .Content etc. to variables at the start (where you may add to scratch etc.), e.g:

{{ $mypartialThatProcessesImages := partial "foo.html" . }}
<html>
<head>
/.... read from scracth
...
</head>
<body>
{{ $mypartialThatProcessesImages}}
</body>
...

Thanks for that.

Ill work out how this might work with my script and post back when I’ve spent some time testing it.

I think I might have to set up a “main” block and a “hints” block.

From the single/list.html

{{ define "hints" }}
{{ partial "image.html" . }} 
// assign the <img> or <picture> tag to scratch 
// add image hints
{{ end }}
{{ define "main" }}
{{ partial "inject" }}
// read from scratch
// inject <im> or <picture>
{{ end }}

As you can see its getting complex and probably wouldn’t work with shortcodes :frowning:

Preloading images seems like a really bad idea, and quite user-hostile. You will force a users browser to download images they may not want or even ever see, eating up bandwidth and cpu, making the user wait longer, and for what?

There’s a reason native lazy-loading has been shipped in all major browsers. Your approach goes in the complete opposite direction. Good UX requires that you respect user settings (low-data?) and preferences (low-energy?), pre-loading images does neiter.

I’d suggest that you’ll achieve better performance, better metrics and better UX by using loading=lazy on your images unless they appear above the fold, and in that case still don’t preload! Images are not render-blocking, by design, so don’t make them render-blocking!

1 Like

Thanks for the info.

What are your thoughts on loading=“eager” for above the fold? Would this improve load speed if I have set up placeholder padding to prevent reflow? Or is lazy sufficient in this case?

I regards to preload, I was only chasing it down because the next.js image doc says preload is better than eager. next/image | Next.js

What are your thoughts on lazy vs eager vs preload for above the fold?

Is lazy above the fold generally better because the user gets the page + placeholders quickly?

My personal preference is to use loading=auto and leave it to the browser to decide.

Things are a little different with Next/Nuxt/React beacuse the image references may not exist in the html before the page is hydrated, so the browser needs to be prompted/primed to expect iomage that it would otherwise have no way of knowing were going to be included. With static html that is not the case, as soon as the html is parsed the browser will know about those images even if they have not yet been downloaded.

When I know the image will be above the fold, as in a hero, I will set loading=auto in all other cases I would use loading=lazy. You can prevent document reflow, without placeholder images or padding, by simply adding the height and width attributes of the original image to your img element. Modern browsers are smart enough to calculate the instrinsic image ratio from that and set the height of the replaced element accordingly.

For the backstory to this behaviour see: A more elegant and easier to use solution · Issue #16 · WICG/intrinsicsize-attribute · GitHub

FWIW, my image partial would typically look something like this:


{{ $src := (.Params.cover_img ) }}
{{ $alt := ( .Params.cover_img_alt ) }}
{{ $img := resources.GetMatch (printf "**%s" ($src)) }}

{{ with $img }}
  {{- $xl := $img.Fill "800x600 jpg" -}}
  {{ $lg := $xl.Resize "600x" -}}
  {{ $md := $lg.Resize "400x" -}}
  {{ $sm := $md.Resize "300x" -}}

  <img
    alt="{{ $alt }}"
    class=object-fit
    loading=lazy
    src="{{ $sm.RelPermalink }}"
    srcset="
    {{ $sm.RelPermalink }} 300w,
    {{ $md.RelPermalink }} 400w,
    {{ $lg.RelPermalink }} 600w,
    {{ $xl.RelPermalink }} 800w"
    sizes="(min-width: 100em) 33vw, 96vw"
    height="600"
    width="800" />
{{ end }}

It’s probably also worth noting that you can also set aspect ratio on elements with css, though in the case of images I believe it is preferable to set the height/width attributes directly.

Thanks so much for your input.

I will do some more work on my image processing module and post back here if I have any questions that need clarification.

1 Like

No problem. Related: images from markdown, with dimensions, a simplified example: Images without width and height from markdown - #14 by nternetinspired

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.