Skip to content

Image

Images are an integral part of the web. They are used to convey information, enhance the visual appeal of a website, and improve user engagement. However, images can also be a significant source of performance bottlenecks if not optimized properly

  • When a picture has an area that is filled with exactly the same colour, it is known as flat colour

Image Formats

Some of the most commonly used image formats on web are:

FormatFile ExtensionLossy/LosslessTypical UsesAdvantagesDisadvantages
JPEG.jpg, .jpegLossyPhotographs, images with continuous tonesHigh compression ratio, widely supportedCan degrade image quality with repeated editing
PNG.pngLosslessGraphics with transparency, logos, iconsSupports transparency, lossless compression, good color accuracyLarger file sizes than JPEG
WebP.webpLossy or losslessWeb images, photographsSmaller file sizes than JPEG and PNG, supports transparency and animationLess widely supported than JPEG or PNG
AVIF.avifLossy or losslessWeb images, photographsSmaller file sizes than JPEG and PNG, supports HDR, wider color gamutLess widely supported than JPEG or PNG
GIF.gifLosslessAnimated images, simple graphicsSupports animation, lossless compression, widely supportedLimited color palette (256 colors), larger file sizes than PNG
SVG.svgLosslessVector graphics, logos, iconsScalable, high-quality graphics, small file sizesCan be complex to edit, might not render consistently across different browsers

NOTE

Lossy formats compress images by discarding some data, resulting in smaller file sizes but potential image quality degradation. Lossless formats compress images without losing any data, preserving the original image quality

JPEG

Joint Photographic Experts Group (JPEG) is a lossy image format that is widely used for photographs and images with continuous tones

  • Most widely used
  • Good for photographs and images with continuous tones
  • Images with many different colours
  • Lossy compression
  • High compression ratio
  • Can be compressed to a smaller file size
  • Supports 24-bit colour

PNG

Portable Network Graphics (PNG) is a lossless image format that is commonly used for graphics with transparency, logos, and icons

  • Supports transparency (old browsers such as IE6 doesn't support)
  • Lossless compression
  • Good colour accuracy
  • Larger file sizes than JPEG
  • Supports 24-bit colour
  • Images with fewer colours or large areas of same colour
  • Used mainly for logos and place where image background transparency is needed
  • Convert PNG to JPEG if no special requirement is there
  • Use WebP image format if transparency is required, Use a backup PNG src as WebP is not yet widely supported as of now

WebP

  • Alternative to JPEG/PNG

  • Smaller file sizes compared to JPEG and PNG

  • It can be used for both lossy (JPEG) and losses (PNG) image compression

  • It also supports transparency like PNG

  • Less support as of now, we can use JPEG/PNG as a fall back image:

    html
    <picture>
      <source width="100%" type="image/webp" srcset="riga.webp" />
      <img width="100%" src="riga_cjpeg_dssim.jpg" alt="Riga, Lativa" />
    </picture>

AVIF

AVIF is a newer format that offers superior compression compared to JPEG and PNG, especially for images with complex details or high dynamic range (HDR) content

html
<picture>
  <source type="image/avif" srcset="snow.avif" />
  <img alt="Hut in the snow" src="snow.jpg" />
</picture>

GIF

  • Short animations

According the GIF89a Specification the GIF is not intended for animations

As a result when a video is converted to GIF the file size increase

So most of the websites like twitter, Facebook etc,. Use video files for animations as they are much smaller than GIF's. These video files can be of MP4 or WebM format

Some tips to convert GIF to videos:

  • Reduce the video colours to 256 colours (GIF supports only 256 colours)

  • Remove audio

  • Using FFmpeg tool to convert GIF to an MP4 or a WebM video, like:

    bash
    ffmpeg -i my-animation.gif -b:v 0 -crf 25 -f mp4 -vcodec libx264 -pix_fmt yuv420p my-animation.mp4
    bash
    ffmpeg -i my-animation.gif -c:v libvpx-vp9 -b:v 0 -crf 41 my-animation.webm

    WebM is a relatively new file format and WebM videos are much smaller than MP4 videos

    WARNING

    Not all browsers support WebM so it makes sense to generate both

  • Usage:

    html
    <video loop autoplay muted playsinline controls="false" src="goats.mp4" />

    OR

    html
    <picture>
      <source type="video/mp4" srcset="goats.mp4" />
      <source type="image/webp" srcset="goats.webp" />
      <img src="goats.gif" alt="Goat" />
    </picture>

    OR

    html
    <video autoplay loop muted playsinline>
      <source src="my-animation.webm" type="video/webm" />
      <source src="my-animation.mp4" type="video/mp4" />
    </video>

    Mobile browsers won't auto play videos unless they are muted

SVG

Scalable Vector Graphics (SVG) is an XML-based vector image format for defining two-dimensional graphics, having support for interactivity and animation

  • The SVG specification is an open standard developed by the World Wide Web Consortium since 1999
html
<svg role="img" aria-labelledby="icon-title icon-desc">
  <title id="icon-title">Pickling Solution</title>
  <desc id="icon-desc">
    The secret to good pickled cheese is good pickling.
  </desc>
  <!-- svg content -->
</svg>

Benefits of <svg>:

  • Can be displayed as regular <img>
  • Can be incorporated in HTML document
  • Can be defined once and used many times
  • Can be styled using CSS
  • Can be made accessible
  • As it made up of text, it can be compressed using GZip or Brotli

For basic, uncomplicated, or decorative images, use the <img> tag and reference the SVG as a file

  • Renders lighter and faster pages overall (versus inline SVGs) and allow for easier maintenance on SVGs that you use in multiple places
html
<img
  role="img"
  class="lightbulb"
  alt="Lightbulb moment!"
  src="https://upload.wikimedia.org/wikipedia/commons/2/2b/BulbIcon.svg"
/>

<!--or-->

<img
  role="img"
  class="lightbulb"
  aria-label="Lightbulb moment!"
  src="https://upload.wikimedia.org/wikipedia/commons/2/2b/BulbIcon.svg"
/>

For more complex or essential SVGs, you should consider adding the SVG as markup into the HTML

  • The page is now potentially heavier and slower
  • But you have more options with JavaScript and CSS to manipulate the styles and animations of the images
html
<svg
  role="img"
  aria-labelledby="lightbulb11 description11"
  version="1.1"
  class="hotpink"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  x="0px"
  y="0px"
  viewBox="0 0 32 32"
  style="enable-background:new 0 0 32 32;"
  xml:space="preserve"
  fill="currentColor"
  width="1em"
  height="1em"
>
  <title id="lightbulb11">Lightbulb moment!</title>
  <desc id="description11">I have a great idea.</desc>
  <path
    d="M11 24h10v2H11zm2 4h6v2h-6zm3-26A10 10 0 0 0 6 12a9.19 9.19 0 0 0 3.46 7.62c1 .93 1.54 1.46 1.54 2.38h2c0-1.84-1.11-2.87-2.19-3.86A7.2 7.2 0 0 1 8 12a8 8 0 0 1 16 0a7.2 7.2 0 0 1-2.82 6.14c-1.07 1-2.18 2-2.18 3.86h2c0-.92.53-1.45 1.54-2.39A9.18 9.18 0 0 0 26 12A10 10 0 0 0 16 2"
  />
</svg>

Modern Image Delivery Techniques

You want your website to be blazing fast, so you have minified and compressed all the files delivered to the user. But still there is a significant delay in page loading time. This is because of the images being used on the web page

According to some analysis of website loading time, it was concluded that nearly 50% of the network traffic was being consumed by the images. Which requires is a lot of network bandwidth. So, to improve the page load time we need to optimize the images and the way they are being delivered

As per google lighthouse, here are 4 Simple ways of Image Optimizations

  1. Quality
  2. Formats
  3. Sizing - Image Dimensions
  4. Lazy Loading

Network Info can help in image optimization, like check if the user's network is slow, then we can send smaller images or less images

  • navigator.connection.type; - Network type that browser uses

  • navigator.connection.downlink - Effective bandwidth estimate

  • navigator.connection.rtt - Effective round-trip time estimate

  • navigator.connection.downlinkMax - Upper bound on the downlink speed of the first network hop

Avoid Base 64 Encoding (Images embedded as Base64 in HTML/CSS/JS) because:

  • Images Block the Rendering of the Page
  • Images are 20-30% larger
  • Caching is limited
  • Difficult to reference more than once
  • The only advantage of this is Fewer Request

Quality

Quality of the images matter, a blurry or pixelated image depletes the user experience. So, we want to delivery images which have the similar image quality of the original but are much smaller in size

Image Dimensions

Using responsive images decreases the page loading time

If the website is viewed on a desktop we need a large image, but if the same website is being viewed on a mobile phone then we can use the smaller image as the view-port is smaller. This will reduce the size of the image being delivered to the mobile, thus decreasing the page load time. Which will enhance the user experience

We can load different images depending on the screen size using the srcset attribute of img tag. We will add all differently sized image sources and let the browser select the image according to the screen size or pixel density of the device

  • srcset is a set of one or more strings separated by commas indicating a set of possible image sources for the user agent to use

  • Usage:

    html
    <!-- Change image depending on DPR (Device Pixel Ratio) -->
    <img
      src="cat-500px.jpg"
      srcset="cat-500px.jpg 1x, cat-1000px.jpg 2x, cat-1500px.jpg 3x"
      atl="cat"
    />
    
    <!-- Change image depending on screen width and (DPR) -->
    <img
      src="cat-500px.jpg"
      srcset="cat-500px.jpg 500w, cat-1000px.jpg 1000w, cat-1500px.jpg 1500w"
      atl="cat"
    />
  • Also using sizes we can optimize even more. sizes lets us use different images based on media queries

    html
    <img
      src="cat-500px.jpg"
      srcset="cat-500px.jpg 500w, cat-1000px.jpg 1000w, cat-1500px.jpg 1500w"
      atl="cat"
      sizes="(min-width: 760px) calc(50vw - 2em), 100vw"
    />

    Use the w unit (instead of px) to write width descriptors. For example, a 1024px wide image would be written as 1024w

WARNING

  • srcset is not widely support as of now, so use a fall-back image source src.

  • The resource specified by the src attribute should be large enough to work well on all device sizes.

DANGER

25% (percentages cannot be used with the sizes attribute)

Images with higher resolutions are larger in size and take longer to load. To optimize the loading time of images, we can use the srcset attribute to provide multiple image sources with different resolutions

  • Images for web should be not more than 72 ppi (pixels per inch)
ResolutionImage File Size (approx.)Image Dimensions (approx.)Description
72 ppi100 KB1920 x 1080Web images
150 ppi200 KB1920 x 1080Print images
300 ppi400 KB1920 x 1080High-quality print images
600 ppi800 KB1920 x 1080Images for professional printing, such as books, magazines, and brochures

sharp

The sharp npm package is a good choice for automating image resizing (for example, generating multiple sizes of thumbnails for all the videos on your website). It is fast and easily integrated with build scripts and tools. On the other hand, ImageMagick CLI tool is convenient for one-off image resizing because it is used entirely from the command line.

Node script to convert images using sharp:

javascript
const sharp = require("sharp");
const fs = require("fs");
const directory = "./images";

fs.readdirSync(directory).forEach((file) => {
  sharp(`${directory}/${file}`)
    .resize(200, 100) // width, height
    .toFile(`${directory}/${file}-small.jpg`);
});

ImageMagick can be used to resize images but we need to automate this process which might complicate things:

bash
# To resize an image to 33% of its original size
convert -resize 33% flower.jpg flower-small.jpg

# To resize an image to fit within 300px wide by 200px high
## macOS/Linux
convert flower.jpg -resize 300x200 flower-small.jpg

## Windows
magick convert flower.jpg -resize 300x200 flower-small.jpg

We can also use Responsive Breakpoint Generators like to get different image dimensions:

Lazy Loading

Lazy loading is the strategy of loading resources as they are needed, rather than in advance. This approach frees up resources during the initial page load and avoids loading assets that are never used.

Loading only those image currently present in the view-port.

lazysizes is the most popular library for lazy loading images. It is a script that intelligently loads images as the user moves through the page and prioritizes images that the user will encounter soon.

Steps to integrate lazysizes:

  1. Add the lazysizes script to your pages:

    html
    <script src="lazysizes.min.js" async></script>
  2. Add class="lazyload" and add data-src instead of src to all <img> and <picture> tags:

    • Add the lazyload class: This indicates to lazysizes that the image should be lazy loaded.
    • Change the src attribute to data-src: When it is time to load the image, the lazysizes code sets the image src attribute using the value from the data-src attribute.
    html
    <img data-src="flower.jpg" class="lazyload" alt="" />
    
    or
    
    <picture>
      <source type="image/webp" data-srcset="flower.webp" />
      <source type="image/jpeg" data-srcset="flower.jpg" />
      <img data-src="flower.jpg" class="lazyload" alt="" />
    </picture>

Gulp Tasks

Imagemin is an excellent image compression tool, it supports a wide variety of image formats and is easily integrated with build scripts and build tools.

We will use gulp-imagemin plugin for image compression. There are specific imagemin plugins to fine tune the quality of images based on image format. Like:

Image FormatLossy Plugin(s)Lossless Plugin(s)
JPEGimagemin-mozjpegimagemin-jpegtran
PNGimagemin-pngquantimagemin-optipng
GIFimagemin-giflossyimagemin-gifsicle
SVGImagemin-svgo
WebPimagemin-webp
javascript
const pngquant = require("imagemin-pngquant");
const mozjpeg = require("imagemin-mozjpeg");
const imageminWebp = require("imagemin-webp");
const imagemin = require("gulp-imagemin");
const gulp = require("gulp");

gulp.task("default", () => {
  gulp
    .src("images/*")
    .pipe(
      imagemin([
        pngquant({ quality: [0.5, 0.5] }),
        mozjpeg({ quality: 50 }),
        imageminWebp({ quality: 50 }),
      ]),
    )
    .pipe(gulp.dest("images/"));
});

JPEG Tools

  1. openjpeg

    • opj_compress
    • Converts *.pnm, *.pgm, *.ppm, *.pgx, *png, *.bmp, *.tif, *.raw or *.tga formats into jpeg.
  2. libjpeg-turbo

    • Used by mozjpeg
    • cjpeg [options] [filename] > [output filename]
  3. guetzli

    • Slow
  4. mozjpeg

    • Based on libjpeg-turbo.
    • Good quality and fast.
  5. imagemagick

    • All in one image converter
    • convert [options] [filename]
    • magick alias
    • Other tools

References