One of my favorites quotes ever is from Steve Job’s biography by Walter Isaacson.

“If it could save a person’s life, would you find a way to shave ten seconds off the boot time?” he asked. Kenyon allowed that he probably could. Jobs went to a whiteboard and showed that if there were five million people using the Mac, and it took ten seconds extra to turn it on every day, that added up to three hundred million or so hours per year that people would save, which was the equivalent of at least one hundred lifetimes saved per year.”

Isn’t that wonderful to think about? Just a little bit of effort can save so much time. This is a philosophy I apply to almost everything I do, whether it’s trying to save seconds from typing, or decreasing load speeds on my projects, I try to make things as quick and fast-moving as possible.

I’ve tried to bring this to my photo website through many different methods. Even though five million people aren’t visiting my site, it’s important to me that the content loads as quickly as possible. Regardless, it’s just a better experience.

Mobile
Mobile PageSpeed Insights

Desktop
Desktop PageSpeed Insights

It’s taken me a long time before reaching anywhere near these speeds. I’ve been developing this site for about 5 years now, and it started out with a score of about 30. So, how did I manage to improve its performance by so much?

WebP Image Format

WebP images are a new image format for the web developed by Google. It works on all Chromium browsers, as well as Firefox, and its load speeds are crazy fast while keeping the file size to a minimum. Whenever possible, I load WebP images. In fact, the only case I don’t load them is if if the browser doesn’t support it (such as Safari). There are a couple places where I display images.

Thumbnails

The first place any user will see pictures is thumbnails. Here, this is easy for me to display either WebP or JPG - I just use the <picture> tag. It allows us to give many different sources (different file types) and gives a fallback of an <img> tag in case none of them work. This will cover all browser support without me having to do much.

1
2
3
4
5
<picture>
  <source type="image/webp" srcset="image.webp" />
  <source type="image/jpeg" srcset="image.jpg" />
  <img src="image.jpg" />
</picture>

This makes my life super easy, because I just render each image with a <picture> tag and put in the corresponding paths to the WebP and JPG version.

Expanded Images

The second place I show the images is if the user clicks on a thumbnail to view the whole thing. However, adding WebP support for this was kind of tricky. The gallery library I use, Magnific Popup, allows the thumbnail to be clicked by wrapping it in an <a> tag. This means that the href for that tag can only be a single path to one of the images.

So by default, I keep all the paths to the JPGs. However, I use a library called Modernizr to detect if the browser has WebP support. If it does, then I iterate over all of these links and change them to the corresponding WebP address. If there are a lot of thumbnails it’s possible that a user may expand the full JPG image, but more commonly its fast enough to change it all before then.

Responsive Images

Another feature that I have taken advantage of to really improve loading times is by serving responsive images. The idea of this is to serve the smallest possible file thats needed based on screen size and display density. I only do this for thumbnails, because detecting which image to serve manually is too difficult, and the pre-loading gallery feature works well such that a user should typically only have to wait for a single image to load. Especially if its WebP, it doesn’t take too long.

For the responsive thumbnails, I support 4 different sizes: 400px, 600px, 800px, and 1024px. The browser should then automatically choose which one to serve. This saves time by loading smaller images when possible, also using less data. To do this, I again take advantage of the <picture> tag and the different <source>s inside of them.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<picture>
  <source
    type="image/webp"
    sizes="(max-width: 760px) 90vw, (max-width: 1300px) 40vw, 500px"
    srcset="
      image-400w.webp  400w,
      image-600w.webp  600w,
      image-800w.webp  800w,
      image.webp      1024w
    "
  />
  <source
    type="image/jpeg"
    sizes="(max-width: 760px) 90vw, (max-width: 1300px) 40vw, 500px"
    srcset="
      image-400w.jpg  400w,
      image-600w.jpg  600w,
      image-800w.jpg  800w,
      image.jpg      1024w
    "
  />
  <img src="image.jpg" />
</picture>

Script

To generate all of these images and different sizes, I wrote a quick bash script that will automatically do it for all images in the directory.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
for i in $(seq 0 $COUNT)
   do
      cwebp "$DIR"/img/"$FILE_NAME"_"$i".jpg -o "$DIR"/img/"$FILE_NAME"_"$i".webp
      cwebp "$DIR"/thmb/"$FILE_NAME"_"$i".jpg -o "$DIR"/thmb/"$FILE_NAME"_"$i".webp
      for j in "${DIM[@]}"
         do
            convert "$DIR"/thmb/"$FILE_NAME"_"$i".jpg -resize "$j" "$DIR"/thmb/"$FILE_NAME"_"$i"-"$j"w.jpg
            cwebp "$DIR"/thmb/"$FILE_NAME"_"$i"-"$j"w.jpg -o "$DIR"/thmb/"$FILE_NAME"_"$i"-"$j"w.webp
         done
   done

It converts all expanded size images into WebP, and all thumbnails into 3 more sizes of both WebP and JPG.