Created
August 4, 2020 23:09
-
-
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
This file contains hidden or 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
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
this is not totally finished but worth copying