Last modified on 01 Oct 2021.
Because the post Gatsby 101 is too long, I write a separate post just for images in Gatsby.
Rule of thumb
- Static images (icon, logo, favicon): just
importand useimg. svgcannot be used withchildImageSharp, just use<img>with itspublicURL.png,jpgcan be used with<Img>andchildImageSharp.- Data can be used:
jsonoryaml, cannot usejsfor images. - List of images are get up to
edges. Afteredges, there are a loop ofnodes. querycomponents must placed in<StaticQuery />.- Different screen solution: use
fixed. - Different screen size: use
fluid. - Use http://localhost:8000/___graphql to check the
query. - Use
{condition && condition && output}instead of usingif..else... - The relative path of images is compared with the path of data file where the urls are indicated.
Type of images to be processed
Read this post from CSS-Tricks to know which images should be processed, which ones should not.
- No processing required: “static images”, icons and logos, favicons 👉 We can
importand use<img>to directly import them. - Process required: PNG, JPG files, gallery, …
Single photo
Install stuffs following this doc,
npm install --save gatsby-image gatsby-plugin-sharp gatsby-transformer-sharp
Insert directly,
import avatar from "src/images/site/avatar.jpg"
function Header() {
return <img src={logo} alt="Logo" />
}
export default Header
Using data/query
So that we can have the lazing loading / resizing / blur-up (traced placeholder) effects.
npm install --save gatsby-image gatsby-transformer-sharp gatsby-plugin-sharp
Below technique is just for single photos.
// gatsby-config.js
module.exports = {
plugins: [
...
'gatsby-plugin-sharp',
'gatsby-transformer-sharp',
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'images',
path: path.join(__dirname, `src`, `images`),
},
},
],
}
// src/components/Header.js
import { StaticQuery, graphql } from 'gatsby';
import Img from 'gatsby-image';
const Header = ({ data }) => (
<header>
<Img fluid={data.myAvatar.childImageSharp.fluid} />
</header>
)
// src/images/avatar.png
export default props => (
<StaticQuery
query={graphql`
query {
myAvatar: file(relativePath: { eq: "avatar.png" }) {
childImageSharp {
fluid(maxWidth: 150) {
...GatsbyImageSharpFluid
}
}
}
}
`}
render={data => <Header data={data} {...props} />}
/>
)
👉 Most of tutorials like this or this don’t talk about StaticQuery (Gatsby v2). I followed them but it didn’t work, we have to use StaticQuery to make things work! 👉 The reason is that the (old) page query can only be added to page components (in my try, I add in Header.js component). StaticQuery can be used as a replacement of page query, it can be added to any component.[ref]
👉 There are 2 types:
fixed: has a set width and height and is for supporting different screen resolutions. It acceptswidthandheight.fluid: has a max-width and sometimes a max-height, and will create multiple images for supporting different screen sizes. It acceptsmaxWidthandmaxHeight.
You need to use them with fragments like GatsbyImageSharpFixed_tracedSVG or GatsbyImageSharpFluid (more).
Using absolute path
If you want to query to an image in /src/images/example.png, you can use,
export const query = graphql`
query {
file(absolutePath: {
regex: "/\\/src\\/images\\/example\\.png/"
}) {
childImageSharp {
fixed(width: 800) {
...GatsbyImageSharpFixed
}
}
}
}
`
SVG files
gatsby-plugin-sharp / gatsby-image doesn’t handle SVGs or GIFs. If you want to use your svg you, e.g. could import / use it like import yourSVG from './logo_large.svg'.[ref]
Change favicon
Put favicon.png in src/images and then change gatsby-config.js
{
resolve: `gatsby-plugin-manifest`,
options: {
// other stuffs
icon: `src/images/favicon.png`,
},
},
You need to restart gastby to see the result!
Multiple images from data file/folder
Images’ URLs stored in a JSON file
Suppose that we store some images in /src/images/ and we indicate them in a json file like this,
// File /data/AccountItem.json
[
{
"name": "Github",
"icon": "./github.svg",
},
{
"name": "LinkedIn",
"icon": "./linkedin.svg",
},
{
"name": "Math2IT",
"icon": "./math2it.png",
}
]
Images (github.svg, linkedin.svg, math2it.png) are stored in the same folder of your json file, that why we put ./ before them!
❓ There are both png and svg files in the list. We cannot use childImageSharp for svg files. How can we “loop” through each item and consider differently svg and png files?
💡 Read this tutorial to read data from a json file.
1/ Having a json file, in this example, it’s /data/AccountItem.json (you can name it whatwever you want but its name is really important for using later!!!)
2/ Install
npm install gatsby-transformer-json gatsby-source-filesystem --save
3/ Inside /gatsby-config.js, add following (direction in path is the direction to the folder containing your json file),
`gatsby-transformer-json`,
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'data',
path: `${__dirname}/data/`,
},
}
4/ Suppose that we wanna load images in a component /src/components/ListAccount.js. Put in it,[ref]
import { StaticQuery, graphql } from 'gatsby';
import Img from 'gatsby-image'
const ListAccount = ( {accounts} ) => (
<div>
{accounts.map(account => (
<div className="item">
<div className="img">
{!account.node.icon.childImageSharp
&& (account.node.icon.extension === 'svg')
&& <img src={account.node.icon.publicURL} />
}
{account.node.icon.extension !== 'svg'
&& <Img fixed={account.node.icon.childImageSharp.fixed} />
}
</div>
</div>
))}
</div>
)
export default props => (
<StaticQuery
query={graphql`
query AccountItemsQuery {
allAccountItemsJson{
edges{
node{
name
icon{
childImageSharp {
fixed(width: 150, height: 150) {
...GatsbyImageSharpFixed_tracedSVG
}
}
extension
publicURL
}
}
}
}
}
`}
render={data => <ListAccount accounts={data.allAccountItemsJson.edges} {...props} />}
/>
)
Explaination:
- We have to put
extensionandpublicURLinsideiconbecause there aresvgfiles! - For more intuition, look at http://localhost:8000/___graphql.
- In
edges, there are manynodes, each of them is relating to the item insideAccountItem.json. That’s why the input data for<ListAccount />must bedata.allAccountItemsJson.edges. - For each
accountinaccounts, we have to passaccount.nodebefore each attributename,icon. {condition && condition && output}is a trick for not usingif...else.
👉 In the case you store images in a different folder, let’s say /src/images/accounts/, you have to indicate it in /data/AccountItems.json:
[
{
"icon": "../src/images/accounts/github.svg",
}
]
Using YAML data file
Suppose our yaml file,
// File /data/AccountItem.yaml
- name: Github
icon: ./github.svg
- name: LinkedIn
icon: ./linkedin.svg
- name: Math2IT
icon: ./math2it.png
The same technique as in the case of json file. In this case, we need to install gatsby-transformer-yaml,
npm install --save gatsby-transformer-yaml
In your gatsby-config.js,
`gatsby-transformer-yaml`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: 'data',
path: `${__dirname}/data/`,
},
},
query as an input
In the previous step, query is considered inside the component file. What if you wanna query data and then pass it in a JSX components? (check index.js for an example)
There is a data file /data/MostProudOfItems.yaml.
// in /src/pages/index.js
import ShortcutListing from "../components/ShortcutListing"
const indexPage = (props) => (
<ShortcutListing
shortcuts={props.data.allMostProudOfItemsYaml.edges}
nShortcutsPerRow='3' />
)
export default IndexPage
export const pageQuery = graphql`
query IndexQuery {
allMostProudOfItemsYaml{
edges {
node {
title
img {
childImageSharp {
fixed(width: 100, height: 100) {
...GatsbyImageSharpFixed_tracedSVG
}
}
extension
publicURL
}
url
}
}
},
anotherYaml{
....
}
}
`
// in /src/components/ShortcutListing
const ListShortcut = ({shortcuts, nShortcutsPerRow}) => (
// ...
)
export default ListShortcut
Get all images from a specific folder
👉 This is also a way you use the name indicate in gatsby-config.js.
[ref]
Suppose that you wanna show all images in /sketches/.
// In /gatsby-config.js
{
resolve: "gatsby-source-filesystem",
options: {
path: `${__dirname}/sketches/`,
name: "sketchFolder",
},
},
export const pageQuery = graphql`
query IndexQuery {
allFile(filter: {
extension: {regex: "/(jpg)|(jpeg)|(png)/"},
sourceInstanceName: {eq: "sketchFolder"}})
{
edges {
node {
childImageSharp {
fluid {
originalName
}
}
absolutePath
}
}
}
}
`
💢 Above method is only works with /sketches (folder locates at the root of site). It doesn’t work with /src/images/sketches, for example. I don’t know why!
👉 If you want to get all images from a folder (without using sourceInstanceName) you can use relativeDirectory in the query. Suppose that we have 2 folders with the same name sketches, one is in /content/sketches, one is in /src/images/sketches. The following code will load all images in these two folders!
// In /gatsby-config.js
{
resolve: "gatsby-source-filesystem",
options: {
path: `${__dirname}/content/`,
name: "content",
},
},
{
resolve: "gatsby-source-filesystem",
options: {
path: `${__dirname}/src/images`,
name: "images",
},
},
export const pageQuery = graphql`
query IndexQuery {
allFile(filter: {
extension: {regex: "/(jpg)|(jpeg)|(png)/"},
relativeDirectory: {eq: "sketches"}})
{
edges {
node {
childImageSharp {
fluid {
originalName
}
}
absolutePath
}
}
}
}
`
💢 Make sure the name of your folder is unique if you don’t want to load images from a wrong location.
References
- A comprehensive guide to images in Gatsby by James Allardice.
- Image Processing with
gatsby-transformer-sharp. - Building A Custom, Accessible Image Lightbox In GatsbyJS