This is the third article about image optimization I implemented in my blog on Nuxt with Netlify CMS.
Check previous ones if you haven’t already:
In this article, I’m going to talk about how I implemented all this on my website. What worked and what didn’t.
Let’s start with the images set using HTML.
This is how it’s done with me:
<img
src="/img/sample_image.png?nf_resize=fit&w=250"
loading="lazy"
alt=". . ."
/>
I add ?nf_resize&w=250
to load an image with a width reduced to 250 pixels and proportional heigh.
Why I chose 250px
? I checked what is the maximum width of the particular image when it’s rendered and set the width accordingly.
On my site, images usually are shown in different sizes. For desktop browsers, it’s fixed width. On mobile, it’s wired to screen width, so it could range from 30px
to 236px
(something like this), so I simply chose 250px
since it never gets bigger than this.
Additional parameters that can be specified on image request from Netlify Large Media you may find in docs.
Adding loading="lazy"
say that browser should load an image only when it’s close to the viewable viewport.
When I didn’t set that at the beginning, the page loaded in the following way: on page open, browser paints the first HTML and starts loading all images used on the current page and until it finishes page are shown as loading. If the page contains many pictures, that take time. Sometimes a lot.
When you set loading="lazy"
browser loads only images that are in the viewable part of the page and in the area of 1250px
-2500px
down it (doc). At least on Chromium browsers it should work this way.
So, yeah, it could speed up page load a lot, since loading first 3 images and then others, as needed, is faster than loading more at once😉.
However, I didn’t set this for the first images on the pages, as advised officially here. These images are anyway going to be loaded on the page open🙂.
srcset
and sizes
I also tried to do responsive image loading with the following code from Mozilla:
<img srcset="path_to_image.png?nf_resize=fit&w=180 180w,
path_to_image.png?nf_resize=fit&w=250 250w"
sizes="(max-width: 400px) 180px,
250px"
src="path_to_image.png?nf_resize=fit&w=250"
alt=". . ."
/>
As from code, it means that on screens with a width up to 400 pixels browser should request an image with this parameters: ?nf_resize=fit&w=180 180w
. Hence with a width of 180 pixels. While on screens with a width of more than 400 pixels, it should load an image with this parameters: ?nf_resize=fit&w=250 250w
. So the width should be 250 pixels.
But these didn’t work.
When specifying sizes
in the percentage of vw
(viewport), everything works, as you will see later on with Markdown images. But with px
specifications nothing worked. Images were always loading with this parameters: ?nf_resize=fit&w=250 250w
🤷♂️.
After playing with it for some time, I understood that I could simply leave it with one ?nf_resize=fit&w=250 250w
parameter. As I had before, like this:
<img
src="/img/sample_image.png?nf_resize=fit&w=250"
loading="lazy"
alt=". . ."
/>
My images become really responsive on mobile, and figuring out correct vw
for different layouts is a considerable pain (at least for me).
I have also downloaded images to compare their sizes. 250px
one was 114 kb, where 180px
one was 63,3 kb. Quite twice a difference, but after running Page Speed tests with 180px
image, I didn’t see any improvements🤷♂️.
Doing all this optimization for blog posts is a bit more complicated.
All my posts are written in Markdown and gets converted into HTML by markdown-it plugin.
Markdown language has some specifications and limitations on how images are described. Here is the structure of the image specification: ![Alt text people will see if picture can’t be seen](https://link.of/image “Title to show under the image”)
. Not so many things we could specify. Luckily we can do a lot of modification on how Markdown is translated to HTML with the additional markdown-it-
plugins.
First of all, I found and added a plugin that adds loading=”lazy”
to every image that is rendered by markdown-it.
Here is it: markdown-it-image-lazy-loading. ! If you are also planning to load optimized images by adding URL parameters to images, then wait a bit before adding it. There is a way to use only the plugin I will show next without the need to install this one. Just proceed to the next section.
After setting loading="lazy"
loading speed of blog pages with many images rocketed. This attribute is really must-have. Check the results in the next article.
srcset
and sizes
Then I tried adding markdown-it-responsive package that should add srcset
and sizes
attributes to every image, but this didn’t work at all. I have been getting HTML rendering error and broken pages☹️.
After some additional search, I have found this plugin: markdown-it-modify-token. After checking it, I understood that it would work great, and I can do everything I need with it.
Some time and this code was born:
modifyToken: function(token, env) {
switch (token.type) {
case "image":
token.attrObj.srcset =
`${token.attrObj.src}?nf_resize=fit&w=300 300w, ` +
`${token.attrObj.src}?nf_resize=fit&w=600 600w`;
token.attrObj.src = token.attrObj.src + "?nf_resize=fit&w=600";
break;
}
},
By specifying srcset
this way I’m saying to the browser: here is two images, with the width of 300px
and 600px
, decide by yourself what image to load according to 100% viewport width.
First I also added size
attribute, this way:
token.attrObj.sizes = “100vw”;
But removed it after reading Chris Coyier article. It’s the default value for the browser, so no need to specify that additionally.
It works, but the behaviour is a bit strange (at least for me). When screen width is 200px
browser load image with 300px
width, but when screen width is set to 250px
image with 600px
width is loaded… I don’t understand that😐.
And again specifying sizes
in px
only led to 600px
image to be loaded…
Here is code I have tried:
token.attrObj.sizes = "(max-width: 400px) 300px, 600px"
Ok, I will just leave sizes as 100vw
and let the browser decide when to load what. Hope browser is smart.
As I wrote before, the usage of markdown-it-image-lazy-loading plugin could be dropped here for additional code in
modifyToken: function(token, env) {
}
Just add this:
token.attrObj.loading = "lazy";
Here, in case "image":
:
switch (token.type) {
case "image":
token.attrObj.srcset =
`${token.attrObj.src}?nf_resize=fit&w=300 300w, ` +
`${token.attrObj.src}?nf_resize=fit&w=600 600w`;
token.attrObj.src = token.attrObj.src + "?nf_resize=fit&w=600";
// This will make all images loading lazy
token.attrObj.loading = "lazy";
break;
}
By the way, if you want to always load images with one size, just remove srcset
setter. It would look this way:
switch (token.type) {
case "image":
token.attrObj.src = token.attrObj.src + "?nf_resize=fit&w=600";
// token.attrObj.loading = "lazy";
break;
}
As you remember, it’s better to have the first images without lazy load, but it’s a bit hard to do with images from Markdown. Additional logic should be written for markdown-it, and the time investment is not really worth it for me. Yes, there is a small drop a performance, as guys from Google say, but it won’t break the bank, I think.
That’s all I have done for better image loading on my site. In the next article, you could check page speed improvements I got. They are quite solid😉.
By the way, you always can change the share text.
By the way, you always can change the share text.