Skip to content

Instantly share code, notes, and snippets.

@jeffscottward
Created August 4, 2020 23:09
Show Gist options
  • Save jeffscottward/eebcdf31493d9e14b18e374c999172f9 to your computer and use it in GitHub Desktop.
Save jeffscottward/eebcdf31493d9e14b18e374c999172f9 to your computer and use it in GitHub Desktop.
A React.js based picture fallback system for all devices all file types all resolutions and shows them accordingly depending on how many breakpoints you supply
const Picture = ({ name, path = "images/", bp = [] }) => {
let viewports = {};
let sizes = ["1x", "2x", "3x"];
let fileExtensions = {
svg: "svg+xml",
webp: "webp",
png: "png",
jpg: "jpeg",
gif: "gif"
};
if (Array.isArray(bp)) {
if (bp.length === 0) {
// if no breakpoints - assume desktop only
viewports.desktop = `(min-width: 1px)`;
}
if (bp.length === 1) {
// if one breakpoint - assume mobile and desktop
viewports.mobile = `(max-width: ${bp[0]})`;
viewports.desktop = `(min-width: calc(${bp[0]} + 1px)`;
}
if (bp.length === 2) {
// if two breakpoints - assume mobile tablet desktop
viewports.mobile = `(max-width: ${bp[0]})`;
viewports.tablet = `(min-width: calc(${
bp[0]
} + 1px) and (max-width: calc(${bp[1]} - 1px)`;
viewports.desktop = `(min-width: ${bp[1]})`;
}
} else {
throw Error(`
You must supply an array for breakpoints
\n 1. Empty array means desktop only
\n 2. One array element means mobile and desktop
\n 3. Two array elements means mobile, tablet (in-between), and desktop`);
}
return (
<picture style={{ display: "inline-block" }}>
{Object.keys(viewports).map((device, deviceIdx) => {
return Object.keys(fileExtensions).map(
(fileExtension, fileExtensionIdx) => {
return (
<source
srcSet={`${path}${name}${`-` + device}.${fileExtension} ${
sizes[0]
}, ${path}${name}${`-` + device}@${sizes[1]}.${fileExtension} ${
sizes[1]
}, ${path}${name}${`-` + device}@${sizes[2]}.${fileExtension} ${
sizes[2]
}`}
type={`images/${fileExtensions[fileExtension]}`}
media={viewports[device]}
key={device + deviceIdx + fileExtension + fileExtensionIdx}
data-device-info={device}
/>
);
}
);
})}
{/* ------------------ Total Fallback ------------------ */}
<img
src={`${path}${name}.png`}
srcSet={`${path}${name}@${sizes[sizes.length - 1]}.png ${
sizes[sizes.length - 1]
}`}
alt={`${name}-fallback`}
/>
</picture>
);
};
export default Picture
@jeffscottward
Copy link
Author

this is not totally finished but worth copying

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