使用 Render Hooks 在 Hugo 中实现响应式图片
Responsive images in Hugo using Render Hooks

原始链接: https://mijndertstuij.nl/posts/hugo-responsive-images-using-render-hooks/

## 使用 Hugo Render Hooks 实现现代响应式图片 本文详细介绍了一种在 Hugo 中生成响应式图片的新方法,不再使用 2022 年使用的短代码方法。随着 WebP 得到广泛支持,该过程现在可以通过 Hugo 的 Render Hooks 来简化。 在 layouts 目录下的 `render-image.html` 文件会生成 WebP 和 JPEG 两种版本的图片,并将 `srcset` 属性直接嵌入到单个 `` 标签中。WebP 优先级更高,JPEG 作为旧浏览器的后备方案。该 Hook 会动态地将图片调整为不同的宽度(例如 480px、768px、1024px 等),并利用页面包(将图片与 Markdown 内容放在一起)来改善组织结构。 配置允许在 `config.toml` 中设置默认 WebP 质量(例如 85)。这种简化的方法消除了对 `` 元素和复杂短代码的需求,为 Hugo 项目提供了一种更简洁、更现代的响应式图片解决方案。它利用标准的 Markdown 图片语法,易于使用。

对不起。
相关文章

原文

Back in 2022 I wrote about automatically generating responsive images in both JPEG and WebP formats using Hugo shortcodes. In those days, browser support for WebP was still quite spotty so we had to generate both formats and do a little magic to let the browser fall back to JPEG if needed.

Fast forward to 2026 and WebP is now well supported in all major browsers, and Hugo has also evolved beyond shortcodes in favor of Render Hooks.

The render hook

The actual render hook that generates the resized JPEG and WebP files looks pretty similar to the shortcode, but works slightly differently.

Create a file in layouts/_default/_markup/render-image.html with the following contents:

{{- $src := .Destination -}}
{{- $alt := .Text -}}
{{- $img := .Page.Resources.GetMatch $src -}}
{{- if not $img -}}
  {{- $img = resources.Get $src -}}
{{- end -}}
{{- if $img -}}
  {{- $widths := slice 480 768 1024 1366 1920 -}}
  {{- $origWidth := $img.Width -}}
  {{- $origHeight := $img.Height -}}
  {{- $srcsetEntries := slice -}}
  {{- range $w := $widths -}}
    {{- if le $w $origWidth -}}
      {{- $resized := $img.Process (printf "resize %dx webp q85" $w) -}}
      {{- $srcsetEntries = $srcsetEntries | append (printf "%s %dw" $resized.RelPermalink $w) -}}
    {{- end -}}
  {{- end -}}
  {{- $fallbackWidth := 1024 -}}
  {{- if lt $origWidth 1024 -}}
    {{- $fallbackWidth = $origWidth -}}
  {{- end -}}
  {{- $fallback := $img.Process (printf "resize %dx jpg q85" $fallbackWidth) -}}
  <img
    src="{{ $fallback.RelPermalink }}"
    {{- if $srcsetEntries }}
    srcset="{{ delimit $srcsetEntries ", " }}"
    sizes="(max-width: 768px) 100vw, 720px"
    {{- end }}
    alt="{{ $alt }}"
    width="{{ $origWidth }}"
    height="{{ $origHeight }}"
    {{- if eq .Ordinal 0 }}
    fetchpriority="high"
    {{- else }}
    loading="lazy"
    decoding="async"
    {{- end }}>
{{- else -}}
  <img src="{{ $src }}" alt="{{ $alt }}">
{{- end -}}

As you can see, the <picture> element is no longer used, and instead we directly generate the srcset attribute for the <img> tag and reference the WebP file, with a fallback to the JPEG file in the event the browser doesn't support WebP.

The post and image files

Then in a blog post, likely a Markdown file, you can reference the image like any other and the Render Hook will take care of the rest:

![A random landscape photo](landscape.jpg)

My previous post suggested to put the images in the /assets/images/ directory, but with the Render Hook in place and using the latest Hugo version, you can use something called page bundles. This means you put the images right next to the Markdown file in the same directory.

content/posts/my-post/
    index.md
    hero.jpg

Setting WebP image quality

In your Hugo configuration file, you can set the default quality for WebP images using the imaging configuration. For example:

[imaging]
  quality = 85

[imaging.webp]
  quality = 85

Wrapping up

Compared to the shortcode approach this is a nice simplification. Gone is the <picture> element, the shortcode is gone, just standard Markdown and a single modern Render Hook. Page bundles also make it easier to keep things organized since images live right next to the content.

联系我们 contact @ memedata.com