Lazy load images with the IntersectionObserver API
Lazy loading of images can be a really nice feature for pages with large images.
Usually, to create a lazy load functionality you have to use JavaScript. With a
swap from a data-src to a src attribute you can already achieve this. A
better approach would be using native functionality of the browser. This will
increase performance as JavaScript listeners won’t block the user from loading
new images. Google Chrome already offers this option. With a loading attribute
on your image, the image will be lazy loaded without any JavaScript. The options
for this attribute are:
eager: Will load the resource immediately, regardless of where it's located on the page.auto: Will fall back to the browsers default value, which is the same as not including the attributelazy: Will lazy load the image when it - the screen of the user - reaches calculated distance from the image
The loading attribute requires a width and height to be set. Without dimensions specified, layout shifts can occur, which are more noticeable on pages that take some time to load. Unfortunately the support is very limited.

For this reason I came up with a really simple lazy load JavaScript implementation that uses the IntersectionObserver API as recommended by Google as a fallback. The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport. It has a better support than the loading attribute.

The src attribute is replaced by a data-src to prevent the browser from
loading the image immediately
This will collect all images with the lazy-load attribute and it will change the data-src to the original source. You can even add a loading image as a placeholder, be sure to keep the size of image small.
In Vue you can create a directive for this. The following example is created
for Vue 3 but you can adapt it to Vue 2 as well.
In your Vue template you can now use the following syntax:
Result
With this code I created a small example in Vue 3 with multiple logos with a
padding-top of 50vh so you can scroll to the new image and see the effect.
