Skip to content

Instantly share code, notes, and snippets.

@jimdiroffii
Last active August 6, 2025 01:57
Show Gist options
  • Select an option

  • Save jimdiroffii/e9ee83d9fb906a43f8a8ff8026d8a929 to your computer and use it in GitHub Desktop.

Select an option

Save jimdiroffii/e9ee83d9fb906a43f8a8ff8026d8a929 to your computer and use it in GitHub Desktop.
How to enable JPG fallback for any AVIF image on your website
/* SOURCE: https://gregbenzphotography.com/photoshop/photoshop-now-natively-supports-avif-for-50-smaller-files-than-jpg/
REVISED with corrections and error handling.
*/
function replaceAvifImagesWithPicture() {
const logToConsole = true;
if (logToConsole) console.log("replaceAvifImagesWithPicture()");
// Select all <img> elements with a .avif source that haven't been processed yet.
// We check that its parent is NOT a <picture> element.
const images = document.querySelectorAll('img[src$=".avif"]:not(picture img)');
if (logToConsole) {
console.log(`Found ${images.length} AVIF images to replace.`);
}
images.forEach(async (img) => {
const avifSrc = img.src;
if (logToConsole) {
console.log(`Replacing ${avifSrc} with <picture> element`);
}
// Create the .jpg fallback URL
const jpgSrc = avifSrc.replace(/\.avif$/i, ".jpg");
// Optional: Check if JPG fallback exists (uncomment if needed)
/*
try {
const response = await fetch(jpgSrc, { method: 'HEAD' });
if (!response.ok) {
console.warn(`JPG fallback not found: ${jpgSrc}`);
return; // Skip this image if no fallback exists
}
} catch (error) {
console.warn(`Could not verify JPG fallback: ${jpgSrc}`, error);
return;
}
*/
// Create the <picture> wrapper
const picture = document.createElement("picture");
// Create and append the AVIF source element
const sourceAvif = document.createElement("source");
sourceAvif.type = "image/avif";
sourceAvif.srcset = avifSrc;
picture.appendChild(sourceAvif);
// Create the fallback <img> element
const imgFallback = document.createElement("img");
// Copy all attributes from the original <img> to the new one
for (const attr of img.attributes) {
imgFallback.setAttribute(attr.name, attr.value);
}
// Set the src of the fallback to the JPG version
imgFallback.src = jpgSrc;
// Add error handling for the fallback image
imgFallback.onerror = function() {
console.warn(`Fallback image failed to load: ${jpgSrc}`);
// Optionally, you could set a default placeholder image here
// this.src = '/path/to/placeholder.jpg';
};
// Append the fallback <img> to the <picture> element
picture.appendChild(imgFallback);
// Replace the original <img> with the new <picture> element
img.replaceWith(picture);
});
}
// For better robustness, you might also consider a MutationObserver
// to handle images added to the page dynamically after the initial load.
document.addEventListener("DOMContentLoaded", replaceAvifImagesWithPicture);
@jimdiroffii
Copy link
Author

HTML Alternative - Performed at build time, rather than client-side. WebP fallback is optional.

<picture>
  <!-- AVIF first -->
  <source
    type="image/avif"
    srcset="path/to/image.avif 1x, path/to/[email protected] 2x"
    sizes="(max-width: 800px) 100vw, 800px">

  <!-- WebP fallback -->
  <source
    type="image/webp"
    srcset="path/to/image.webp 1x, path/to/[email protected] 2x"
    sizes="(max-width: 800px) 100vw, 800px">

  <!-- Final JPEG fallback -->
  <img
    src="path/to/image.jpg"
    alt="Description of image"
    width="800"
    height="600"
    loading="lazy"
    decoding="async">
</picture>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment