How images work in Publii

Publii offers multiple ways to modify and display your images; from basic functionality that simply displays an image, to complex markup that delivers differently-sized images at different screen resolutions to strike the perfect balance between aesthetics and speed.

When creating Publii, we wanted to make sure that the markup used with images was clear and understandable so that even less-experienced users that want to start making their own modifications could jump in and find their way. In this post, we’ll take a look at several ways that we can modify images throughout a theme, but before that, we’ll first need to establish the types of images that Publii uses:

Images Types

Publii utilises four different image types that cover particular elements and areas of a Publii website; each of these types comes its own settings defined through the config.json file in the theme's folder. These types are:

Featured Image - This is an image that is added via the sidebar options on the Edit Post page. Usually, this image will be displayed on the article page itself, and will also be used any time a post preview is displayed, such as on post listing pages such as the Frontpage, Tag or Author pages.

Content Image - Content images refers to images that are displayed in the post body; that is, if you insert an image into your article via the editor or by dragging and dropping an image into your post, then it will be defined as a content image.

Option Images - These are images that are defined by the creator of a theme to allow images to be uploaded to theme-specific sections of a page via the Theme Options e.g. if a theme has a unique hero section or slider, then the images used in this section will be classed as option images.

Gallery Images - Refers only to images that are uploaded to and used in a Gallery inserted into a post via the Post Editor.

Content Images and Gallery Images are handled by Publii automatically; these are uploaded or inserted via the editor and they have specific predefined settings for this purpose. However, the Featured Image and Option images are more flexible, so we’ll be looking more closely at them and how we can modify their settings in the following sections.  

Basic

The basic markup for an image is very easy to use and understand; it simply pulls the data stored in the FeaturedImage tags, which are detailed in the following link: https://getpublii.com/dev/featured-image-tags/ 

{{#featuredImage}}
   {{#if url}}
    <img src="{{url}}" height="{{height}}" width="{{width}}" alt="{{alt}}">
  {{/if}}
{{/featuredImage}}

The src, height, width and alt attributes are standard, defining the basic dimensions, the source URL and alt text of the image. Additionally, by using the {{#if url}} condition, we can check whether a featured image has been uploaded or not; no URL means no image, so the additional functions related to the featured image will be ignored.

Intermediate

The basic markup detailed above will display the RAW (original) images, but what if we want to display responsive thumbnails that will adjust their dimensions depending on the current screen resolution?

Publii has built-in functions to take care of the heavy lifting in this case, so we only have to take care of three elements; setting the number of thumbnails, and defining two other attribute - srcset and sizes

For example, if we wanted to generate a set of thumbnails, then we would first need to define them in the config.json file. After opening this file, look for the Files section, where we can define the thumbnails using the following code:

"featuredImages": {
                "sizes": "(max-width: 48em) 100vw, 768px",
                "dimensions": {
                    "xs": {
                        "width": 300,
                         "height": 300,
                        "crop": true
                    },
                    "sm": {
                        "width": 480,
                        "height": "auto"
                    },
                    "md": {
                        "width": 768,
                        "height": "auto"
                    },
                    "lg": {
                        "width": 1024,
                        "height": "auto"
                    }
            }

The code is quite straightforward. The sizes function is used to define some core rules for how images are displayed, and each item in the dimensions section (e.g. xs, sm etc…in the above example), which is collectively the srcset attribute, defines the specific width for each type of image, from very small to large, which will tell the browser which image to show to the user depending on the size of the viewport. With these attributes set, we can modify the featuredImage markup to make use of these attribute:

{{#featuredImage}} 
  {{#if url}} 
    <img 
         src="{{url}}" 
         sizes="{{sizes}}"             
         srcset="{{srcset}}"
         height="{{height}}" 
         width="{{width}}" 
         alt="{{alt}}"> 
  {{/if}} 
{{/featuredImage}}

The above example can be further simplified by making use of responsiveImageAttributes,  which will accept the ‘featuredImage’, srcset and sizes attributes instead of them being separately-defined in the markup:

{{#featuredImage}} 
  {{#if url}} 
    <img 
         src="{{url}}" 
         {{responsiveImageAttributes 'featuredImage' srcset sizes}}
         height="{{height}}" 
         width="{{width}}" 
         alt="{{alt}}"> 
  {{/if}} 
{{/featuredImage}}

Advanced

Publii offers a lot more options for displaying images for users with more experience. Imagine that you wanted to display a large image in the hero section and a smaller one in other sections of the page. For the hero section we’d need several thumbnails, but for the other(s) we’d only need two or three. 

By using the group variable, we can separate them quickly and easily:

"featuredImages": {
                "sizes": {
                    "hero": "(max-width: 1600px) 100vw, 1600px",
                    "other": "(max-width: 768px) 100vw, 768px"
                },

                "dimensions": {
                    "xs": {
                        "width": 300,
                        "height": "auto",
                        "group": "hero,other"
                    },
                    "sm": {
                        "width": 480,
                        "height": "auto",
                        "group": "hero,other"
                    },
                    "md": {
                        "width": 768,
                        "height": "auto",
                        "group": "hero,other"
                    },
                    "lg": {
                        "width": 1024,
                        "height": "auto",
                        "group": "hero"
                    },
                    "xl": {
                        "width": 1360,
                        "height": "auto",
                        "group": "hero"
                    }
            }

As you can see, the specific attributes for each group are separately defined in the sizes section, and then each item in the srcset is applied to a particular group using the group attribute. With this done, we can create the markup for the hero section:

{{#featuredImage}} 
  {{#if url}} 
    <img 
         src="{{url}}" 
         {{responsiveImageAttributes 'featuredImage' srcset.hero sizes.hero}}
         height="{{height}}" 
         width="{{width}}" 
         alt="{{alt}}"> 
  {{/if}} 
{{/featuredImage}}

And a similar markup for the other section:

{{#featuredImage}} 
  {{#if url}} 
    <img 
         src="{{url}}" 
         {{responsiveImageAttributes 'featuredImage' srcset.other sizes.other}}
         height="{{height}}" 
         width="{{width}}" 
         alt="{{alt}}"> 
  {{/if}} 
{{/featuredImage}}

So as you can see, since all the images in the srcset are added to the hero group, they will all be displayed there, whereas only two images were added to the other group, so only two will be displayed in the other section.

Note: Groups can be created only for Featured images

Tips: If you want to display only one specific thumbnail you can do this with the following markup, where the dimension name starts with a capital letter {{urlDimension_name}}

{{#featuredImage}}
   {{#if url}}
    <img src="{{urlXs}}" alt="{{alt}}">
  {{/if}}
{{/featuredImage}}

As you notice, a dimension suffix "Xs" was added to the {{url}}  in the src attribute.

Important: The suffix must start with a capital letter e.g. {{urlSm}} or {{urlMd}}

Content Image

As mentioned above, contentImages are handled by Publii so we don’t need to make any changes unless we want to display them in a responsive manner. We can setup this functionality similarly to how we did it above, in the config.json file: 

"contentImages": {
                "sizes": "(max-width: 48em) 100vw, 768px",
                "dimensions": {
                    "xs": {
                        "width": 300,
                        "height": "auto"
                    },
                    "sm": {
                        "width": 480,
                        "height": "auto"
                    },
                    "md": {
                        "width": 768,
                        "height": "auto"
                    }                
                 }
            }

Options Image

This type of image can be used when you want to allow your users upload their image via the theme settings, rather than pulling them automatically from post featured images or other areas of the theme, such as for a photo slideshow.

To create this kind of image, we’ll first need to create the attributes for the option in the config.json file, so that we can allow an image to be uploaded:

{
   "name": "uploadImage",
   "label": "Image",
   "group": "Hero section",
   "value": "",
   "type": "upload",
   "upload": true
},

Next, we can create the markup for the image; this function defines the source of the image as an upload, rather than existing content in the theme or post content:

<img src="{{@config.custom.uploadImage}}" alt="">

However, this markup only allows the image to be uploaded; to make them responsive, we’ll need to create the srcset in the config.json as before when we created the Content Images, but in this case we’ll need to add the code to the optionImages section:

"optionImages": {
                "sizes": "(max-width: 1600px) 100vw, 1600px",
                "dimensions": {
                    "xs": {
                        "width": 300,
                        "height": 255,
                        "crop": true
                    },
                    "sm": {
                        "width": 480,
                        "height": "auto"
                    },
                    "md": {
                        "width": 768,
                        "height": "auto"
                    },
                    "lg": {
                        "width": 1024,
                        "height": "auto"
                    },
                    "xl": {
                        "width": 1360,
                        "height": "auto"
                    }                }
            }

But these items that we’ve added won’t actually do anything until we expand our image markup to include take the sizes and screen elements into account; once again, the responsiveImageAttributes helper will make this easy:

<img
    src="{{@config.custom.uploadImage}}" 
     {{responsiveImageAttributes @config.custom.uploadImage}}
    alt="">

But what about the image dimensions? Not to worry, another helper, {{imageDimensions}}, will take care of this for us:

<img
    src="{{@config.custom.uploadImage}}" 
     {{responsiveImageAttributes @config.custom.uploadImage}}
     {{imageDimensions @config.custom.uploadImage}}
    alt="">

With the markup finished, our option image is ready to go!

As with content images, galleryImages is mostly handled by Publii. The only thing that we need to define is the maximum size for thumbnails that are generated by the gallery. We can add this info in the galleryImages section of the config.json file:

"galleryImages": {
                "sizes": "",
                "dimensions": {
                    "thumbnail": {
                         "width": 720,
                         "height": "auto"                       
                    }
                }
            }

Lazy load

Since version 1.0 Publii has supported native lazy loading that drastically improves your website load-times by loading images only when they appear in the viewport as the user scrolls.

By default this option is enabled (under Site Settings -> Website speed) and works with all content images including gallery thumbnails, iframes, and video elements.

To implement it with other image types such as Featured or Option images we need only add a single helper: {{ lazyload "options" }}, that can accept the following options:

  • lazy
  • eager
  • auto

Example:

{{#featuredImage}} 
  {{#if url}} 
    <img 
         src="{{url}}" 
         {{responsiveImageAttributes 'featuredImage' srcset sizes}}
         {{lazyload "lazy"}}
         height="{{height}}" 
         width="{{width}}" 
         alt="{{alt}}"> 
  {{/if}} 
{{/featuredImage}}

Note: when the Lazy load option is disabled the helper returns empty output.  

Enable the Responsive Images option

Also since version 0.36, Publii has included the option to completely disable thumbnail generation. When disabled, only the RAW (original) image files are provided to a user’s browser.
For Content Images this option works automatically, but for Feature and Option images we have to use a {{@config.site.responsiveImages}} condition to check if the option is enabled.

{{#featuredImage}} 
  {{#if url}} 
    <img 
         src="{{url}}" 
        {{#if @config.site.responsiveImages}}
            {{responsiveImageAttributes 'featuredImage' srcset.other sizes.other}}
         {{/if}}
         height="{{height}}" 
         width="{{width}}" 
         alt="{{alt}}"> 
  {{/if}} 
{{/featuredImage}}

If the Responsive Image option is disabled the sizes and srcset attributes will not be rendered.