Skip to content

Commit

Permalink
feat(gatsby-remark-images): make images blur up (gatsbyjs#7800)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: html markup has been changed, high resolution image (img.gatsby-resp-image-image) is no longer nested inside span with low resolution placeholder  (span.gatsby-resp-image-wrapper) - it's sibling of that span now. This might affect any custom styling that is applied to inline images
  • Loading branch information
jamesadarich authored and gpetrioli committed Jan 22, 2019
1 parent fcb1704 commit 354bcb2
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 74 deletions.
2 changes: 1 addition & 1 deletion packages/gatsby-remark-images/.babelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"presets": [
["babel-preset-gatsby-package"]
["babel-preset-gatsby-package", { "browser": true }]
]
}
2 changes: 2 additions & 0 deletions packages/gatsby-remark-images/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/constants.js
/gatsby-browser.js
/index.js
/__tests__/*
tests
Original file line number Diff line number Diff line change
@@ -1,119 +1,97 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`it handles goofy nesting properly 1`] = `
"
<span
"<span
class=\\"gatsby-resp-image-wrapper\\"
style=\\"position: relative; display: block; max-width: 300px; margin-left: auto; margin-right: auto;\\"
>
<span
class=\\"gatsby-resp-image-background-image\\"
style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url('url('data:image/png;base64, iVBORw)'); background-size: cover; display: block;\\"
>
<img
></span>
<img
class=\\"gatsby-resp-image-image\\"
style=\\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\\"
style=\\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\\"
alt=\\"test\\"
title=\\"\\"
src=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg\\"
srcset=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg, not-a-real-dir/images/this-image-already-has-a-link.jpeg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
/>
</span>
</span>
"
</span>"
`;

exports[`it leaves images that are already linked alone 1`] = `
"
<span
"<span
class=\\"gatsby-resp-image-wrapper\\"
style=\\"position: relative; display: block; max-width: 300px; margin-left: auto; margin-right: auto;\\"
>
<span
class=\\"gatsby-resp-image-background-image\\"
style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url('url('data:image/png;base64, iVBORw)'); background-size: cover; display: block;\\"
>
<img
></span>
<img
class=\\"gatsby-resp-image-image\\"
style=\\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\\"
style=\\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\\"
alt=\\"img\\"
title=\\"\\"
src=\\"not-a-real-dir/image/my-image.jpg\\"
srcset=\\"not-a-real-dir/image/my-image.jpg, not-a-real-dir/image/my-image.jpg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
/>
</span>
</span>
"
</span>"
`;

exports[`it leaves linked HTML img tags alone 1`] = `
"<a href=\\"https://example.org\\">
<span class=\\"gatsby-resp-image-wrapper\\" style=\\"position: relative; display: block; max-width: 300px; margin-left: auto; margin-right: auto;\\">
<span class=\\"gatsby-resp-image-background-image\\" style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url(&apos;url(&apos;data:image/png;base64, iVBORw)&apos;); background-size: cover; display: block;\\">
<img class=\\"gatsby-resp-image-image\\" style=\\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\\" alt=\\"this image already has a link\\" title=\\"\\" src=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg\\" srcset=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg, not-a-real-dir/images/this-image-already-has-a-link.jpeg\\" sizes=\\"(max-width: 650px) 100vw, 650px\\">
</span>
<span class=\\"gatsby-resp-image-background-image\\" style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url(&apos;url(&apos;data:image/png;base64, iVBORw)&apos;); background-size: cover; display: block;\\"></span>
<img class=\\"gatsby-resp-image-image\\" style=\\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\\" alt=\\"this image already has a link\\" title=\\"\\" src=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg\\" srcset=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg, not-a-real-dir/images/this-image-already-has-a-link.jpeg\\" sizes=\\"(max-width: 650px) 100vw, 650px\\">
</span>
</a>"
`;
exports[`it leaves single-line linked HTML img tags alone 1`] = `
"
<span class=\\"gatsby-resp-image-wrapper\\" style=\\"position: relative; display: block; max-width: 300px; margin-left: auto; margin-right: auto;\\">
<span class=\\"gatsby-resp-image-background-image\\" style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url(&apos;url(&apos;data:image/png;base64, iVBORw)&apos;); background-size: cover; display: block;\\">
<img class=\\"gatsby-resp-image-image\\" style=\\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\\" alt=\\"this image already has a link\\" title=\\"\\" src=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg\\" srcset=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg, not-a-real-dir/images/this-image-already-has-a-link.jpeg\\" sizes=\\"(max-width: 650px) 100vw, 650px\\">
</span>
</span>
"
"<span class=\\"gatsby-resp-image-wrapper\\" style=\\"position: relative; display: block; max-width: 300px; margin-left: auto; margin-right: auto;\\">
<span class=\\"gatsby-resp-image-background-image\\" style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url(&apos;url(&apos;data:image/png;base64, iVBORw)&apos;); background-size: cover; display: block;\\"></span>
<img class=\\"gatsby-resp-image-image\\" style=\\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\\" alt=\\"this image already has a link\\" title=\\"\\" src=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg\\" srcset=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg, not-a-real-dir/images/this-image-already-has-a-link.jpeg\\" sizes=\\"(max-width: 650px) 100vw, 650px\\">
</span>"
`;
exports[`it transforms HTML img tags 1`] = `
"
<a class=\\"gatsby-resp-image-link\\" href=\\"not-a-real-dir/image/my-image.jpeg\\" style=\\"display: block\\" target=\\"_blank\\" rel=\\"noopener\\">
<span class=\\"gatsby-resp-image-wrapper\\" style=\\"position: relative; display: block; max-width: 300px; margin-left: auto; margin-right: auto;\\">
<span class=\\"gatsby-resp-image-background-image\\" style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url(&apos;url(&apos;data:image/png;base64, iVBORw)&apos;); background-size: cover; display: block;\\">
<img class=\\"gatsby-resp-image-image\\" style=\\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\\" alt=\\"my image\\" title=\\"\\" src=\\"not-a-real-dir/image/my-image.jpeg\\" srcset=\\"not-a-real-dir/image/my-image.jpeg, not-a-real-dir/image/my-image.jpeg\\" sizes=\\"(max-width: 650px) 100vw, 650px\\">
</span>
"<a class=\\"gatsby-resp-image-link\\" href=\\"not-a-real-dir/image/my-image.jpeg\\" style=\\"display: block\\" target=\\"_blank\\" rel=\\"noopener\\">
<span class=\\"gatsby-resp-image-wrapper\\" style=\\"position: relative; display: block; max-width: 300px; margin-left: auto; margin-right: auto;\\">
<span class=\\"gatsby-resp-image-background-image\\" style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url(&apos;url(&apos;data:image/png;base64, iVBORw)&apos;); background-size: cover; display: block;\\"></span>
<img class=\\"gatsby-resp-image-image\\" style=\\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\\" alt=\\"my image\\" title=\\"\\" src=\\"not-a-real-dir/image/my-image.jpeg\\" srcset=\\"not-a-real-dir/image/my-image.jpeg, not-a-real-dir/image/my-image.jpeg\\" sizes=\\"(max-width: 650px) 100vw, 650px\\">
</span>
</a>
"
</a>"
`;
exports[`it transforms images in markdown 1`] = `
"
<a
"<a
class=\\"gatsby-resp-image-link\\"
href=\\"not-a-real-dir/images/my-image.jpeg\\"
style=\\"display: block\\"
target=\\"_blank\\"
rel=\\"noopener\\"
>
<span
<span
class=\\"gatsby-resp-image-wrapper\\"
style=\\"position: relative; display: block; max-width: 300px; margin-left: auto; margin-right: auto;\\"
>
<span
class=\\"gatsby-resp-image-background-image\\"
style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url('url('data:image/png;base64, iVBORw)'); background-size: cover; display: block;\\"
>
<img
></span>
<img
class=\\"gatsby-resp-image-image\\"
style=\\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\\"
style=\\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\\"
alt=\\"image\\"
title=\\"\\"
src=\\"not-a-real-dir/images/my-image.jpeg\\"
srcset=\\"not-a-real-dir/images/my-image.jpeg, not-a-real-dir/images/my-image.jpeg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
/>
</span>
</span>
</a>
"
</a>"
`;
3 changes: 3 additions & 0 deletions packages/gatsby-remark-images/src/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
exports.imageClass = `gatsby-resp-image-image`
exports.imageWrapperClass = `gatsby-resp-image-wrapper`
exports.imageBackgroundClass = `gatsby-resp-image-background-image`
35 changes: 35 additions & 0 deletions packages/gatsby-remark-images/src/gatsby-browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const {
imageClass,
imageBackgroundClass,
imageWrapperClass,
} = require(`./constants`)

exports.onRouteUpdate = () => {
const imageWrappers = document.querySelectorAll(`.${imageWrapperClass}`)

// https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/
// for cross-browser looping through NodeList without polyfills
for (let i = 0; i < imageWrappers.length; i++) {
const imageWrapper = imageWrappers[i]

const backgroundElement = imageWrapper.querySelector(
`.${imageBackgroundClass}`
)
const imageElement = imageWrapper.querySelector(`.${imageClass}`)

const onImageLoad = () => {
backgroundElement.style.transition = `opacity 0.5s 0.5s`
backgroundElement.style.opacity = 0
imageElement.style.transition = `opacity 0.5s`
imageElement.style.opacity = 1
imageElement.removeEventListener(`load`, onImageLoad)
}

if (imageElement.complete) {
backgroundElement.style.opacity = 0
} else {
imageElement.style.opacity = 0
imageElement.addEventListener(`load`, onImageLoad)
}
}
}
55 changes: 31 additions & 24 deletions packages/gatsby-remark-images/src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
// const select = require(`unist-util-select`)
const {
imageClass,
imageBackgroundClass,
imageWrapperClass,
} = require(`./constants`)
const visitWithParents = require(`unist-util-visit-parents`)
const path = require(`path`)
const isRelativeUrl = require(`is-relative-url`)
Expand Down Expand Up @@ -90,9 +94,6 @@ module.exports = (
return resolve()
}

// Calculate the paddingBottom %
const ratio = `${(1 / fluidResult.aspectRatio) * 100}%`

const originalImg = fluidResult.originalImg
const fallbackSrc = fluidResult.src
const srcSet = fluidResult.srcSet
Expand All @@ -104,14 +105,18 @@ module.exports = (
const fileNameNoExt = fileName.replace(/\.[^/.]+$/, ``)
const defaultAlt = fileNameNoExt.replace(/[^A-Z0-9]/gi, ` `)

// TODO
// Fade in images on load.
// https://www.perpetual-beta.org/weblog/silky-smooth-image-loading.html

const imageClass = `gatsby-resp-image-image`
const imageStyle = `width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px ${
options.backgroundColor
};`
const imageStyle = `
width: 100%;
height: 100%;
margin: 0;
vertical-align: middle;
position: absolute;
top: 0;
left: 0;
box-shadow: inset 0px 0px 0px 400px ${options.backgroundColor};`.replace(
/\s*(\S+:)\s*/g,
`$1`
)

// Create our base image tag
let imageTag = `
Expand All @@ -124,7 +129,7 @@ module.exports = (
srcset="${srcSet}"
sizes="${fluidResult.sizes}"
/>
`
`.trim()

// if options.withWebp is enabled, generate a webp version and change the image tag to a picture tag
if (options.withWebp) {
Expand Down Expand Up @@ -162,29 +167,31 @@ module.exports = (
src="${fallbackSrc}"
alt="${node.alt ? node.alt : defaultAlt}"
title="${node.title ? node.title : ``}"
src="${fallbackSrc}"
/>
</picture>
`
`.trim()
}

const ratio = `${(1 / fluidResult.aspectRatio) * 100}%`

// Construct new image node w/ aspect ratio placeholder
const showCaptions = options.showCaptions && node.title
let rawHTML = `
<span
class="gatsby-resp-image-wrapper"
class="${imageWrapperClass}"
style="position: relative; display: block; ${
showCaptions ? `` : options.wrapperStyle
} max-width: ${presentationWidth}px; margin-left: auto; margin-right: auto;"
>
<span
class="gatsby-resp-image-background-image"
class="${imageBackgroundClass}"
style="padding-bottom: ${ratio}; position: relative; bottom: 0; left: 0; background-image: url('${
fluidResult.base64
}'); background-size: cover; display: block;"
>${imageTag}</span>
></span>
${imageTag}
</span>
`
`.trim()

// Make linking to original image optional.
if (!inLink && options.linkImagesToOriginal) {
Expand All @@ -196,19 +203,19 @@ module.exports = (
target="_blank"
rel="noopener"
>
${rawHTML}
${rawHTML}
</a>
`
`.trim()
}

// Wrap in figure and use title as caption
if (showCaptions) {
rawHTML = `
<figure class="gatsby-resp-image-figure" style="${options.wrapperStyle}">
${rawHTML}
<figcaption class="gatsby-resp-image-figcaption">${node.title}</figcaption>
${rawHTML}
<figcaption class="gatsby-resp-image-figcaption">${node.title}</figcaption>
</figure>
`
`.trim()
}

return rawHTML
Expand Down

0 comments on commit 354bcb2

Please sign in to comment.