Created
January 15, 2025 14:02
-
-
Save fgnass/4afc16577636d66fff4e0336e9de790a to your computer and use it in GitHub Desktop.
Generate sizes attributes for all responsive images on a page.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Quick helper to generate sizes attributes for your responsive images. | |
// It loads the current page into an invisible iframe and resizes it to the different breakpoints, | |
// where it measures the images and converts their width to vw. | |
// Usage: Open the HTML page you want to add sizes attributes to in your browser, | |
// paste this code in the console and hit return. The result will be logged to the console. | |
(async () => { | |
const sizesData = new Map(); | |
const sizeThreshold = 0.1; // Threshold for grouping similar sizes (in vw) | |
// Define breakpoints | |
const breakpoints = [640, 768, 1024, 1280, 1536]; | |
const viewportWidths = []; | |
// Also probe at +/- 1px | |
breakpoints.forEach((bp) => { | |
viewportWidths.push(bp - 1, bp, bp + 1); | |
}); | |
// Create an iframe to load the site | |
const iframe = document.createElement('iframe'); | |
iframe.style.position = 'fixed'; | |
iframe.style.top = 0; | |
iframe.style.left = 0; | |
iframe.style.width = '100%'; | |
iframe.style.height = '100vh'; | |
iframe.style.visibility = 'hidden'; // Keep iframe hidden | |
document.body.appendChild(iframe); | |
// Load the current page into the iframe | |
iframe.src = window.location.href; | |
await new Promise((resolve) => { | |
iframe.onload = resolve; | |
}); | |
const doc = iframe.contentDocument || iframe.contentWindow.document; | |
console.log("Starting measurements..."); | |
// Function to measure and record sizes | |
const measureSizes = (viewportWidth) => { | |
iframe.style.width = `${viewportWidth}px`; | |
const images = doc.querySelectorAll('img'); | |
images.forEach((img) => { | |
const containerWidth = img.parentElement.offsetWidth; | |
const percentage = parseFloat(((containerWidth / viewportWidth) * 100).toFixed(2)); | |
const key = img.src || img.outerHTML; | |
if (!sizesData.has(key)) { | |
sizesData.set(key, []); | |
} | |
const sizesArray = sizesData.get(key); | |
if (!sizesArray.some((item) => item.viewport === viewportWidth)) { | |
sizesArray.push({ viewport: viewportWidth, size: percentage }); | |
} | |
}); | |
}; | |
// Iterate through viewport widths and measure | |
for (let i = 0; i < viewportWidths.length; i++) { | |
const width = viewportWidths[i]; | |
console.log(`Measuring at width: ${width}px (${i + 1}/${viewportWidths.length})`); | |
measureSizes(width); | |
await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for layout to stabilize | |
} | |
// Remove the iframe | |
iframe.remove(); | |
console.log("Measurement complete. Processing results..."); | |
// Group images by identical `sizes` attributes | |
const groupedData = new Map(); | |
sizesData.forEach((sizesArray, key) => { | |
// Filter and group sizes by skipping insignificant changes | |
const filteredSizes = []; | |
for (let i = 0; i < sizesArray.length; i++) { | |
if ( | |
i === 0 || | |
Math.abs(sizesArray[i].size - sizesArray[i - 1].size) >= sizeThreshold | |
) { | |
filteredSizes.push(sizesArray[i]); | |
} | |
} | |
// Consolidate ranges for clean output | |
const sizesString = filteredSizes | |
.map((entry, index) => { | |
if (index === 0 || filteredSizes[index - 1].viewport + 1 !== entry.viewport) { | |
return `(max-width: ${entry.viewport}px) ${entry.size}vw`; | |
} | |
return null; // Skip redundant entries | |
}) | |
.filter(Boolean) | |
.join(', '); | |
if (!groupedData.has(sizesString)) { | |
groupedData.set(sizesString, []); | |
} | |
groupedData.get(sizesString).push(key); | |
}); | |
// Format and output the grouped results | |
let output = ''; | |
groupedData.forEach((keys, sizesString) => { | |
output += `sizes="${sizesString}"\n`; | |
keys.forEach((key) => { | |
output += ` - ${key}\n`; | |
}); | |
output += '\n'; | |
}); | |
console.log("Results:"); | |
console.log(output); // Log the output for easy copy-paste | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment