DEV Community 👩‍💻👨‍💻

Cover image for Exploring Art Direction to Dynamically Load Images
Monica Powell
Monica Powell

Posted on • Originally published at

Exploring Art Direction to Dynamically Load Images

While updating my homepage to include my newly-commission illustration from Aishwarya Tandon, I wanted to load different versions of the image based on screen-size in a performant way. For my header image, I use gatsby-image, an official GatsbyJS plugin that optimizes images that makes it straightforward to control how images are progressively enhanced on page load. One of my favorite built-in Gatsby image effects is traced SVGs, which renders an SVG tracing of an image, in a pre-determined color before the image fully loads. You can explore all of gatsby-image's built-in loading effects on the using-gatsby-image site.

The above GIF illustrates how gatsby-image transitions from traced SVG to the loaded image

While looking into how to load different images at different breakpoints without unnecessarily downloading files I discovered gatsby-image's built-in support for this feature which is known as art direction. Modern HTML can be used to dynamically load of images based on screen size using srcset attributes with <img> and <source> instead of JavaScript. Swapping images at different screen sizes can be done with JavaScript or CSS instead of native HTML attributes however using the HTML attributes can improve page loading performance as it prevents unnecessarily preloading two images when only one image from the srcset needs to be visible within the viewport on load.

The above GIF shows the transition between different images loaded with art direction within gatsby-image

All images that use the gatsby-image plugin need to be constructed using a GraphQL query. Below is a slightly modified version of the useStaticQuery() I used to load image files into gatsby-image's Img. Within useStaticQuery() I wrote two named queries mobileImage and desktopImage to load both versions of the image I wanted on mobile as well as the desktop.

import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Img from "gatsby-image"

const Avatar = () => {
  const data = useStaticQuery(graphql`
    query {
      mobileImage: file(
        relativePath: { eq: "animonica-headshot-cropped.png" }
      ) {
        childImageSharp {
          fluid(maxWidth: 300, quality: 100) {
      desktopImage: file(relativePath: { eq: "animonica-full.png" }) {
        childImageSharp {
          fluid(maxWidth: 300, quality: 100) {

  const sources = [
      media: `(min-width: 625px)`,

  return <Img fluid={sources} alt="Illustrated Monica" />

export default Avatar

If you inspect my site's header using Dev Tools you'll notice there's two <picture> sections, one that includes the tracedSVGs that are generated by GatsbyImageSharpFluid_tracedSVG in the image query and another with the .png files.

The HTML that ultimately renders to load the .png files from the earlier use of gatsby-image resembles the below:

  <source media="(min-width: 625px)" srcset="animonica-full.png" />
  <source srcset="animonica-headshot-cropped.png" />
  <img src="animonica-full.png" alt="Illustrated Monica" />

The media attribute in the <source> elements, within <picture>, determines which image srcset is displayed. The first condition that is met will be displayed, in the case where neither media condition is true or the browser doesn't support the <picture> element it will return the <img> element from within the <picture>. You can view current browser compatability for <picture> at Can I use this?.

As a recap, within gatsby-image we can pass an array of images to generate HTML's art direction related attributes. Using this approach instead of CSS or JavaScript reduces the number of assets that need to be preloaded in the browser. My current Gatsby site, displays a complete HTML page from the server to the client on the initial load without requiring JavaScript therefore I've found it helpful to avoid delegating certain tasks to JavaScript that HTML/CSS can handle in a more performant way. I've written more about this topic in my article Less JavaScript Makes Font Awesome More Awesome.

The article was originally published at

Top comments (0)

🤔 Did you know?

📚 You can adjust your experience level in Settings to see more relevant content.