Skip to main content

Simple Image Placeholders with SVG

By Tyler Sticka

Published on January 7th, 2020

Topics

We do a lot of rapid prototyping at Cloud Four, which means we’re often working with incomplete or hypothetical content. When it comes to FPO images, we’ve relied on a few different solutions:

Each of these techniques has strengths and weaknesses. For us, external requests slowed down refreshes during local development, client-side libraries were more failure-prone and introduced modest performance hiccups, and it was a drag having to stop prototyping to go search for, resize and save stock images manually.

So I made a tiny, dependency-free library called Simple SVG Placeholder. It generates data URIs for placeholder img elements.

Consider this typical placeholder image:

300×150

If you were to “hand code” this image as an SVG, it might look something like this:

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="150" viewBox="0 0 300 150">
  <rect fill="#ddd" width="300" height="150"/>
  <text fill="rgba(0,0,0,0.5)" font-family="sans-serif" font-size="30" dy="10.5" font-weight="bold" x="50%" y="50%" text-anchor="middle">300×150</text>
</svg>Code language: HTML, XML (xml)

Our JavaScript function looks very similar, except we use template literals so that details like size, color and typography may be customized:

const str = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
  <rect fill="${bgColor}" width="${width}" height="${height}"/>
  <text fill="${textColor}" font-family="${fontFamily}" font-size="${fontSize}" dy="${dy}" font-weight="${fontWeight}" x="50%" y="50%" text-anchor="middle">${text}</text>
</svg>`;Code language: JavaScript (javascript)

Then we clean up and encode the string so it can be used as a Data URI. This portion takes a lot of inspiration from Filament Group’s SVG URI Encoder, but simplified since we know more about our source markup:

const cleaned = str
  .replace(/[\t\n\r]/gim, '') // Strip newlines and tabs
  .replace(/\s\s+/g, ' ') // Condense multiple spaces
  .replace(/'/gim, '\\i'); // Normalize quotes

const encoded = encodeURIComponent(cleaned)
  .replace(/\(/g, '%28') // Encode brackets
  .replace(/\)/g, '%29');

return `data:image/svg+xml;charset=UTF-8,${encoded}`;Code language: JavaScript (javascript)

The result is a string we can use as the src attribute for an img element!

As mentioned earlier, our greatest need for placeholder images is while prototyping. We do a lot of that work in-browser using some sort of template engine to streamline the process.

First, we install the Simple SVG Placeholder package:

npm i --save @cloudfour/simple-svg-placeholderCode language: Bash (bash)

Then we use the function to build a template helper. If our project uses Handlebars, the helper might look like this:

// Include the function
const simpleSvgPlaceholder = require('@cloudfour/simple-svg-placeholder');

// Optionally establish project-specific defaults
const defaults = {
  bgColor: '#0F1C3F',
  textColor: '#7FDBFF'
};

// Register the helper
Handlebars.registerHelper('placeholderImage', block => {
  const options = block.hash || {};
  return simpleSvgPlaceholder({ ...defaults, ...options });
});Code language: JavaScript (javascript)

Then we can use our helper in templates:

<img src="{{placeholderImage width=800 height=450}}" alt="">Code language: Handlebars (handlebars)

Which compiles to a data URI containing the placeholder image:

<img src="data:image/svg+xml;…" alt="">Code language: HTML, XML (xml)

Which displays in the browser:

800×450

Simple SVG Placeholder has a bunch more options detailed in its README. It’s available now via GitHub, NPM, Yarn, and so on. I hope you dig it!