Skip to content

Image Placeholders ​

imgx provides several techniques for generating lightweight image placeholders that can be used for lazy loading, improving perceived performance and user experience.

Why Use Placeholders? ​

Image placeholders serve several important purposes:

  • Faster Initial Page Load: Tiny placeholders (typically <1KB) load almost instantly
  • Reduced Layout Shift: Reserving space for images prevents content jumping
  • Progressive Enhancement: Users see a preview while the full image loads
  • Better UX: Creates a smoother, more polished loading experience

Placeholder Strategies ​

imgx supports several placeholder generation strategies:

StrategyDescriptionSizeVisual Quality
BlurLow-resolution, blurred version of the image~500-800 bytesMedium
ThumbHashAdvanced algorithm that preserves colors and shapes~100-300 bytesHigh
Dominant ColorSingle color that represents the image~30-50 bytesLow
PixelateLow-resolution, pixelated version of the image~200-500 bytesMedium

Basic Usage ​

CLI ​

bash
# Generate a placeholder with the default strategy (blur)
imgx placeholder image.jpg

# Specify a strategy
imgx placeholder image.jpg --strategy thumbhash

# Adjust the size of the placeholder
imgx placeholder image.jpg --width 30

# Save the placeholder to a file
imgx placeholder image.jpg --output placeholder.webp

JavaScript/TypeScript API ​

ts
import { createPlaceholder } from '@stacksjs/imgx'

// Generate a blur placeholder
const blurPlaceholder = await createPlaceholder('path/to/image.jpg')

// Generate a ThumbHash placeholder
const thumbhash = await createPlaceholder('path/to/image.jpg', {
  strategy: 'thumbhash',
})

console.log(`Data URL: ${thumbhash.dataURL}`)

Placeholder Strategies in Detail ​

Blur Strategy ​

The blur strategy creates a tiny version of the image and applies a Gaussian blur:

bash
imgx placeholder image.jpg --strategy blur --width 20 --blur-level 40
ts
const placeholder = await createPlaceholder('image.jpg', {
  strategy: 'blur',
  width: 20, // Width in pixels (height is calculated automatically)
  blurLevel: 40, // 0-100, higher = more blur
  quality: 50, // 0-100
  format: 'webp', // webp, jpeg, or png
})

ThumbHash Strategy ​

ThumbHash is an advanced algorithm that creates compact, visually pleasing thumbnails:

bash
imgx placeholder image.jpg --strategy thumbhash
ts
const placeholder = await createPlaceholder('image.jpg', {
  strategy: 'thumbhash',
})

ThumbHash is the recommended approach for most use cases due to its superior quality-to-size ratio.

Dominant Color Strategy ​

This strategy extracts the dominant color from the image:

bash
imgx placeholder image.jpg --strategy dominant-color
ts
const placeholder = await createPlaceholder('image.jpg', {
  strategy: 'dominant-color',
  saturation: 1.2, // Adjust color saturation (default: 1.2)
})

console.log(`Dominant color: ${placeholder.dominantColor}`) // e.g., "#3a7bd5"

Pixelate Strategy ​

This strategy creates a low-resolution pixelated version of the image:

bash
imgx placeholder image.jpg --strategy pixelate --width 16
ts
const placeholder = await createPlaceholder('image.jpg', {
  strategy: 'pixelate',
  width: 16, // Width in pixels (smaller = more pixelated)
})

Output Formats ​

Data URLs ​

By default, placeholders are returned as base64-encoded data URLs that can be directly used in HTML or CSS:

html
<img src="data:image/webp;base64,UklGRuYAAABXRUJQVlA4..." alt="Image">

CSS ​

For dominant color placeholders, imgx can generate CSS:

bash
imgx placeholder image.jpg --strategy dominant-color --css-filter

This returns CSS properties that can be applied:

css
.placeholder {
  background-color: #3a7bd5;
  filter: contrast(1.1);
}

File Output ​

You can save placeholders to files:

bash
imgx placeholder image.jpg --output placeholders/thumb.webp --base64=false

HTML Implementation Examples ​

Basic Implementation ​

html
<div class="image-container">
  <!-- Placeholder (loads immediately) -->
  <img
    src="data:image/webp;base64,UklGRuYAAABXRUJQVlA4..."
    class="placeholder"
    alt="Description"
  >

  <!-- Full image (loads lazily) -->
  <img
    src="full-image.jpg"
    class="full-image"
    loading="lazy"
    alt="Description"
    onload="this.style.opacity=1; this.previousElementSibling.style.opacity=0;"
  >
</div>

With CSS:

css
.image-container {
  position: relative;
  aspect-ratio: 16/9; /* Match your image aspect ratio */
}

.placeholder,
.full-image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity 0.3s;
}

.full-image {
  opacity: 0;
}

Using with Modern Image Components ​

For frameworks like React:

jsx
import React, { useState } from 'react'

function LazyImage({ src, placeholderDataUrl, alt, ...props }) {
  const [loaded, setLoaded] = useState(false)

  return (
    <div className="image-container">
      <img
        src={placeholderDataUrl}
        className={`placeholder ${loaded ? 'hidden' : ''}`}
        alt={alt}
      />
      <img
        src={src}
        className={`full-image ${loaded ? 'visible' : ''}`}
        alt={alt}
        loading="lazy"
        onLoad={() => setLoaded(true)}
        {...props}
      />
    </div>
  )
}

Batch Processing Placeholders ​

You can generate placeholders for multiple images at once:

bash
imgx batch ./images --placeholders --strategy thumbhash --output-dir ./placeholders

Or programmatically:

ts
import { batchProcess } from '@stacksjs/imgx'

const result = await batchProcess('./images/**/*.jpg', {
  placeholders: {
    strategy: 'thumbhash',
    outputDir: './placeholders',
  },
})

Configuration ​

You can set default placeholder options in your imgx.config.ts file:

ts
// imgx.config.ts
export default {
  placeholders: {
    width: 20,
    quality: 50,
    format: 'webp',
    blurLevel: 40,
    base64Encode: true,
    useThumbhash: false,
    strategy: 'blur', // 'blur', 'pixelate', 'thumbhash', 'dominant-color'
    saturation: 1.2,
    cssFilter: false,
  },
}

Released under the MIT License.