Skip to content

Instantly share code, notes, and snippets.

@whmountains
Last active September 5, 2017 15:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save whmountains/40efd2f6d0a709a8c0e7d7475c4b201e to your computer and use it in GitHub Desktop.
Save whmountains/40efd2f6d0a709a8c0e7d7475c4b201e to your computer and use it in GitHub Desktop.
React Responsive Image Component for Gatsby

React Responsive Image component for Gatsby

A tiny, base64 version of the image gets inlined into the document, while the larger version is loaded and overlayed on top. The <img> element for the full-size version has a srcset attribute, so the browser will only download the resolution that it needs.

NPM Dependencies:

  • gatsby-plugin-sharp
  • gatsby-transformer-sharp
  • styled-components
  • auto-bind

Basic usage

<Image info={this.props.data.img} />

The info prop needs to come from your page's graphql query. Here's an example query, assuming that your image is named splash-bg.jpg:

img: imageSharp(id: { regex: "/splash-bg/" }) {
  ...imageInfo
}

Override width and height

The width and height props accept any CSS <length> values.

  • Set only one value, and the other will be set automatically based on the image's aspect ratio.
  • Set both values, and the image will scale to cover the area you've defined.
<Image info={this.props.data.img} width='100%' height='50vh' />

The fill keyword is shorthand for width={100%} height={100%}

<Image info={this.props.data.img} fill />
// Example for how to set up your gatsby-config.js to load images
module.exports = {
siteMetadata: {
title: `Some Title`,
},
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-plugin-sharp`,
`gatsby-transformer-sharp`,
`gatsby-plugin-styled-components`
]
}
import React from 'react'
import styled from 'styled-components'
import autoBind from 'auto-bind'
const Container = styled.div`
position: relative;
overflow: hidden;
background-color: #f6f6f6;
${p => `width: ` + p.width + ';'}
${p => `height: ` + p.height + ';'}
`
const Img = styled.img`
position: absolute;
top: 0;
left: 0;
transition: opacity 0.5s linear;
margin: 0;
width: 100%;
height: 100%;
object-fit: cover;
object-position: ${p => p.position};
`
const AspectRatioPreserver = styled.div`
width: 100%;
padding-bottom: ${p => 100 / p.ratio}%;
`
export default class Image extends React.Component {
constructor () {
super()
autoBind(this)
this.state = {
imgLoaded: false
}
}
loadFullImage () {
this.setState({
imgLoaded: true
})
}
render () {
const image = this.props.info.responsiveSizes
const imageOpacity = ((!this.state.imgLoaded) && this.props.blurIn) ? 0 : 1
const position = this.props.position || 'center'
let height = this.props.height
let width = this.props.width
if (this.props.fill) {
height = '100%'
width = '100%'
}
return (
<Container
height={height}
width={width || this.props.imgWidth}
className={this.props.className} >
<AspectRatioPreserver ratio={image.aspectRatio} />
<Img blur src={image.base64} position={position} />
<Img
srcSet={image.srcSet}
src={image.src}
onLoad={this.loadFullImage}
style={{opacity: imageOpacity}}
position={position} />
</Container>
)
}
}
export const imageQuery = graphql`
fragment imageInfo on ImageSharp {
responsiveSizes(quality: 80) {
base64
aspectRatio
src
srcSet
sizes
originalImg
}
}
`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment