Hugo responsive images

GitHub License GitHub release (latest SemVer including pre-releases) GoLang version" Awesome

Hugo responsive images makes generating responsive images for either figures or standard picture elements a breeze.

Minimal inline code is required and configuration can take place either inline or in your site's config file.

The project generates both fixed width responsive images (1x,2x etc) and variable width responsive images for responsive pages. All of Hugo's powerful image processing options have been exposed.

You images will have a default class of img-fluid (Bootstrap responsive image), but you can set this in the config, or inline.

Installation (as a module)

# config.yaml
module:
  imports:
  - path: github.com/future-wd/hugo-responsive-images

Prerequisites

  • You must install the latest GoLang (minimum 1.12). See https://golang.org/dl/.
  • You must have a VCS client e.g. git. See https://git-scm.com/downloads/.
  • Install the latest hugo (at least 0.83.0)
  • You hugo project must be initialized for hugo modules e.g. hugo mod init github.com/username/project in the root of your project.
  • Update your modules with hugo mod get -u

Configuration - Site Config

The first set of configuration items are from Hugo's image processing configuration. See the docs for more info..

All the hugo image options can be set at a partial/shortcode level. See below

You can suppress the no alt text error with the ignoreErrors config. If you suppress the error, the ALT text will default to "image of [title]` (title defaults to the page's title)

imaging:
  anchor: Smart # for smart cropping when setting the fillRatio
  bgColor: '#ffffff' # when converting transparent images to formats which dont support transparency
  hint: photo # for conversin to webp
  quality: 75 # compression quality
  resampleFilter: Box # compression filter
ignoreErrors: ["alt-error"] # suppress error message if no alt text has been provided.

If setting imaging options at a site level, this is the best method. You can also use image parameters if you wish to set image options just for this module, although this would probably be best used at a page level.

params:
  image:
    anchor: Smart
    bgColor: "#ffffff"
    hint: photo
    quality: 75
    resampleFilter: Box

Configuration - Site or page params (Defaults shown)

params:
  image:
    widths: [600, 900, 1300] # widths to generate if widths not specified
    # shortcodeWidths: [600, 900, 1300] # custom widths for shortcode use in markdown files. If unset defaults to widths
    # renderHookWidths: [600, 900, 1300] # custom widths for render hook use in markdown files. If unset defaults to shortcode widths
    densities: [1,2] # densities which are output when an image width is specified
    formats: [webp, original] # set output formats. options are `original`, `bmp`, `gif`, `jpeg`, `jpg`, `png`, `tif`, `tiff`, and `webp`. In order of least supported to most supported.
    class: img-fluid # default image class if no class is specified
    figureClass: "figure img-fluid" # default figure class
    figcaptionClass: figure-caption # default figcaption class
    figureImageClass: "figure-img img-fluid" # default figure image class (appended to image class) ## USE .class inline
    figureTitleH: 4 # heading level for figure title
    renderHookWrapperClass: img-wrapper # image wrapper class for render hook
    shortcodeWrapperClass: img-wrapper # image wrapper class for shortcode
    loading: lazy # or auto/lazysizes # lazy/auto are for stock browser behavior, lazysizes will use lazysizes.js 
    sizes: user # or lazysizes # uses lazysizes to automatically generate the sizes property
    renderHook: false # set to false to disable included markdown image render hook
                      # override by setting imageRenderHook: true/false in front matter
    # placeholder: lqip # or dominant/file_name  (see colours set up in assets/images/placeholder-colors) use filename without .gif
    lqipBlurAmount: 5 # apply gaussian blur amount of 5 to lqip
                      # may need to be increased at a page level for larger images
    lqipDivAmount: 5 # lqip is 5x smaller than the smallest image in srcset
    gifDivAmount: 10 # single color gif placeholder is 10x smaller than smallest image in srcset
    # provider: netlify # currently only supports netlify image processing.
    # suppressWidthWarning: true # turn off image too narrow warning
    # type: page # or global # useful for setting all images on a page to global resources, or set default

All of image parameter configuration items can also be configured on a per page basis by adding the config to the page's front matter.

For example:

---
title: About 
image:
  widths: [400, 750, 1300]
---

Partial or shortcode configuration

The following options are only available at a partial or shortcode level:

# image and figure
"src" "image_path.jpg" # relative to page, or assets folder (for global resource)
"title" "Image Title" # defaults to figureTitle, and then the page's title
"class" "img-fluid" # class for image (not a figure image)
"alt" "Image Alt Text"
"fillRatio" (slice 4 3) # width by height, image will be cropped. 
"width" 300 # for fixed with image
"widths" (slice 500 900 1500) # for responsive images
# figure only
"figureTitle" "Title for figure caption" # can be left blank
"caption" "Figure Caption Text"
"attr" "Author Attribution"
"attrLink" "Attribution link"

The following options can be configured at a partial/shortcode & page/site config level

See above for explanations

# image and figure (with partial example)
{{ partial "image" (dict 
  "densities" (slice 1 2)
  "type" "page"
  "formats" (slice "original" "jpg")
  "provider" "netlify"
  "loading" "lazy"
  "sizes" "100vw"
) }}

# figure only

"target" "_blank"
"rel" "noopener noreferrer"
"link" "https://gohugo.io"
"figureClass" "figure-img img-fluid"
"figureCaptionClass" "figure-caption"
"figureTitleH" 4

# placeholder options

"placeholder" "lqip" # set to lqip, dominant, [file_name] or false
"lqipDivFactor" 5 # smallest image in srcset is divided by this number for LQIP size
"lqipBlurAmount" 5 # amount of gaussian blur to apply to LQIP
"gifDivFactor" 10 # dominant/gif file is resized to this division factor (of smallest image in srcset)

# hugo image processing options - if setting at a site level, its recommended to use hugos native image config

"quality" 75
"rotate" 0
"resampleFilter" "box"
"hint" "photo"
"anchor" "smart"
``

> See below for examples of how to set these options from within a shortcode

## Usage Examples

###  Partial - Fixed width & page resource

```html
{{ partial "image"  (dict
  "page" .
  "src" "image.jpg"
  "width" "300"
  )}}

A "type" of "page" does not need to be provided. Default behavior is page resource images.

By providing the "width" key, you will be generating a fixed with image.

"src" is relative to the page's directory

Partial - Fixed with & gobal resource

{{ partial "image"  (dict
  "page" .
  "src" "image.jpg"
  "width" "300"
  "type" "global"
  )}}

Partial - Responsive width & page resource

{{ partial "image" (dict
  "src" "images/image.jpg"
  "page" .
  // if in config sizes=user (not needed for sizes=lazysizes) 
  "sizes" [string] // set the sizes property for the image tag, defaults to "100vw"
  // optional 
  "widths" (slice 400 800 1200) // override default responsive widths.
  ) }}

You don't need to provide the "widths" key to generate responsive width images, this is the default behavior and the widths config will be used.

Partial - Cropping an image to an aspect ratio

{{ partial "image"  (dict
  "page" .
  "src" "image.jpg"
  "fillRatio" (slice 4 3)
  ) }}

Shortcode - Cropping an image to an aspect ratio, custom respnsive widths

{{< image src=image.jpg fillRatio=4,3  widths=400,900 >}}

The page context is already provided by the shortcode

Double quotes (" ") don't have to be used for the property values if there are no spaces.

Comma seperated values are converted into arrays, numbers are converted into integers.

Shortcode - Single positional parameter

{{< image image.jpg >}}

The alt text will default to "image of [page title]" You will need to suppress the alt error (see above)

Partial - Figure

{{ partial "figure"  (dict
  "page" .
  "src" "image.jpg" 
  "figureTitle" "Boat x54"
  "caption" "My favourite boat"
  "link" "https://www.google.com"
  ) }}

Usage as a markdown render hook

By default a markdown render hook template has been included. To turn it on set the config params.image.renderHook: true. It has been disabled by default as it may break existing functionality.

The render hook will only render page resource images - the image path will be relative to the page's markdown file.

You can set configuration at a page or site level e.g.

  • make all images on the page global (image.type: global)
  • turn on the render hook just for one page (image.imageRenderHook: true)
  • set the widths for the page (image.widths: [400, 900])

Render hook only responsive widths default to shortcode responsive widths, and then standard widths. See above for site/page configuration. (image.RenderHookWidths > image.ShortcodeWidths > image.widths)

A div wrapper around the image has been provided see above for configuration (image.renderHookWrapperClass)

You can also set configuration via image resources meta data using the following example:

---
resources:
- src: img1.jpg
  title: Optionally Set title here
  params:
    alt: Optionally set alt here
    width: 300
    class: custom-class # etc
---

Then..

![](img1.jpg)

(I have opted to set alt and title via frontmatter to make the example more informative..)

Placeholder

Displaying a placeholder image while the actual image is loading is dependent on the use of lazysizes.js for the purpose of swapping the image. loading: lazysizes must be set in site/page configuration, or per image.

The configuration item placeholder has three options; lqip, dominant (dominant color used), or specify an image in the assets/images/placeholder-images directory, without the .gif extension. False can be used to override a placeholder configuration at a page or partial/shortcode level.

The following colours (based on bootstrap) have been provided:

  • white
  • gray-100
  • gray-200
  • gray-300
  • gray-400
  • gray-500
  • gray-600
  • gray-700
  • gray-800
  • gray-900
  • black

To create a custom color, make a 10px x 10px gif image with only 1 color and save it in the directory and then call it by its file name, without the .gif extension.

Lqip gaussian blur amount can be adjusted with the lqipBlurAmount configuration item in site/page configuration, or per image.

Lqip image size division factor can be adjusted with the lqipDivFactor configuration item in site/page configuration, or per image. It is based off the smallest image in the srcset.

Dominant/single color gif image size division factor can be adjusted with the gifDivFactor configuration item in site/page configuration, or per image. It is based off the smallest image in the srcset.

example config:

#config.yaml
params:
  images:
    loading: lazysizes # must be set as lazysizes will swap out the placeholder on load
    placeholder: lqip   # or dominant or file_name e.g. gray-300 
    # config below this line is not required if not changing the defaults
    lqipBlurAmount: 5 # apply gaussian blur amount of 5 to lqip
                      # may need to be increased at a page level for larger images
    lqipDivFactor: 5 # lqip is 5x smaller than the smallest image in srcset
    gifDivFactor: 10 # single color gif placeholder is 10x smaller than smallest image in srcset

Setting up Lazysizes.js

Add required CSS for sizes property to work

img[data-sizes="auto"] { display: block; width: 100%; }
/* so bootstrap 5 figures display correctly */
.figure {display: block}

Import inline via CDN

https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.3.2/lazysizes.min.js

JavaScript Module via NPM

Install

npm install lazysizes

Import core package

import 'lazysizes';

Add native lazyloading plugin

import lazySizes from 'lazysizes';
import 'lazysizes/plugins/native-loading/ls.native-loading';

lazySizes.cfg.nativeLoading = {
  setLoadingAttribute: true, // adds loading="lazy" to match non-native behavior
  disableListeners: {
    scroll: true // speeds up browser by not listening to scroll if native lazy load support detected
  },
};

Module configuration

params:
  image:
    loading: lazysizes
    sizes: lazysizes

Contribution

Issues and pull requests are welcome. If need be, make changes to the test site directly in this repository.

Test site is visible @ https://hugo-responsive-images.netlify.app/

Test site resides in /.testSite

Parameters

Name Inline Meta Page Param Site Param Description Default
src YES NO NO NO Provide resource path undefined
type YES YES YES YES page/global - Type of image resource "page"
title YES YES NO NO Image title figureTitle then the page's .Title
fillRatio YES YES YES YES Fill ratio for image null
widths YES YES YES YES Widths for responsive width image generation [600, 900, 1300]
width YES YES YES NO Set widths for fixed with image. Disables widths 'null'
densities YES YES YES YES Densities for fixed with image generation [1,2]
formats YES YES YES YES Image formats to generate. One must be original. In order of browser support. ["original", "webp" ]
provider YES YES YES YES External image processing provider. Only netlify supported for now null
loading YES YES YES YES auto/lazy/lazysizes - Type of image loading "auto"
sizes YES YES YES YES [string]/lazysuzes - Image sizes for responsive widths images "100vw"
class YES YES YES YES Image class "img-fluid"
alt YES YES NO NO Image alt text caption (see figure parameters)

Placeholder variables

Name Inline Meta Page Param Site Param Description Default
placeholder YES YES YES YES lqip/dominant/[gif file name] - Set the placeholder type null
lqipDivFactor YES YES YES YES Division factor for lqip gif size 5
lqipBlurAmount YES YES YES YES Amount of gaussian blur for lqip 5
gifDivFactor YES YES YES YES Division factor for solid gif placeholder 10

Image processing parameters (overrides hugo image processing defaults if set at any level)

See for settings

Name Inline Meta Page Param Site Param Description
quality YES YES YES YES Override hugo image processing default
rotate YES YES YES YES Override hugo image processing default
resampleFilter YES YES YES YES Override hugo image processing default
hint YES YES YES YES Override hugo image processing default
anchor YES YES YES YES Override hugo image processing default

Figure Specific Parameters

Name Inline Meta Page Param Site Param Description Default
link YES YES NO NO Figure image link null
target YES YES YES YES Figure link or attrLink target "_blank" for http links
rel YES YES YES YES Figure link or attrLink rel "noopender, noreferrer" for http links
figureClass YES YES YES YES Figure class "figure"
figureImageClass YES YES YES YES Figure image class "figure-img img-fluid"
figureCaptionClass YES YES YES YES Figcaption class "figure-caption"
figureTitleH YES YES YES YES Figcaption title level 4
figureTitle YES YES NO NO Figcaption Title null
attr YES YES NO NO Figcaption atttribute null
attrLink YES YES NO NO Figcaption attribute link null
caption YES YES NO NO Figcaption caption null