Gatsby: Set Background Image with CSS

Gatsby: Set background image with CSS

Generally I keep component-specific images alongside their JSX and CSS files and general/global images in an images folder, so I might have a structure like this:

.
├── components
│   ├── button.jsx
│   ├── button.module.scss
│   └── button_icon.png
└── images
└── logo.png

To reference button_icon.png from button.module.css I would do this:

background-image: url("./button_icon.png");

And to reference logo.png from button.module.css I would do this:

background-image: url("../images/logo.png");

Update: Lately I've been using Emotion with my Gatsby projects, which requires a slightly different approach. This would work with StyledComponents or Glamor as well:

import background from "images/background.png"
import { css } from "@emotion/core"

// Object styles:
<div css={{ backgroundImage: `url(${background})` }} />

// Tagged template literal styles:
const backgroundStyles = css`
background-image: url(${background});
`
<div css={backgroundStyles} />

Gatsby set background-image CSS-In-JS (Emotion)

So as stated in the link you posted in the comment, there's multiple ways to include image/assets with gatsby:

  1. Query the image from graphql
  2. import the image, get path
  3. Copy the image to static directory

Set up

Say you have a component like this:

// src/pages/sample.js

import React from 'react'
import { css } from '@emotion/core'

export default () => <div css={css`
width: 10rem;
height: 10rem;
background: url( ... );
`} />

Query it

PublicURL

If you're using any of the default starters, it's likely that your src/images folder has been set up with gatsby-source-file-system so Gatsby know about your images. Say you know the name of the file, you can query it like so:

{
// ⇣ `base` is file name with extension.
file (base: { eq: "image.png" }) {
publicURL
}
}

As described in the link, querying the field publicURL will give you the path to the file name:

export default ({ data }) => <div css={css`
width: 10rem;
height: 10rem;
background: url(${data.file ? data.file.publicURL : 'your/fallback.png'});
`} />

export const query = graphql`
query {
file(base: { eq: "image.png" }) {
publicURL
}
}
`

ImageSharp

Gatsby usually comes with sharp, which allows you to transform images & more. For a simple example, this query resize the image to 200px width:

export const query = graphql`
query {
file(base: { eq: "image.png" }) {
childImageSharp {
fixed(width: 200) {
src
}
}
}
}
`

And you can access it at data.file.childImageSharp.fixed.src.

Import the image

Let webpack handle it:

import myImagePath from '../relative/path/to/image.png';

export default () => <div css={css`
width: 10rem;
height: 10rem;
background: url(${myImagePath});
`} />

Copy it to static directory

Create a directory named static at your root folder, unless there's one already. Copy your image into it:

root
|--src
`--static
`--image.png

All files in static will be copy directly to build, so you can link to the image like this:

export default () => <div css={css`
width: 10rem;
height: 10rem;
background: url(/image.png);
`} />

If you're using pathPrefix in gatsby-config.js, import withPrefix from gatsby and wrap it around the image path.


Here's a codesandbox for the first 2 methods.

Hope that helps!

How do I make a background image that fills the screen in Gatsby?

If you want to use it as a background image, you need to make it's container wider and higher to adapt it to the maximum with and height of the screen. Using relative units may work for you. Something like:

.landingDiv {
background-image: url("https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80");
height: 100%;

/* Center and scale the image nicely */
background-position: center;
background-repeat: no-repeat;
background-size: cover;

/* making it 100% of the total width and height */
height: 100vh;
width: 100vw;
}

vh and vw stand for viewport height and viewport width respectively.

How to use gatsby background image plugin

As per your GraphQL, you are using a Gatsby version greater or equal than 3. I think your snippet should look like something like:

import React from 'react'
import { graphql, useStaticQuery } from 'gatsby'
import { getImage, GatsbyImage } from "gatsby-plugin-image"

import { convertToBgImage } from "gbimage-bridge"
import BackgroundImage from 'gatsby-background-image'

const GbiBridged = () => {
const { bgImage }= useStaticQuery(
graphql`
query {
bgImage : file(relativePath: {eq: "background.png"}) {
childImageSharp {
gatsbyImageData(quality: 90)
}
}
}
`
)
const image = getImage(bgImage)
const backgroundImage= convertToBgImage(image)

return (
<React.Fragment>
<GlobalStyle />
<BackgroundImage
Tag="section"
{...backgroundImage}
preserveStackingContext
>
<div style={{minHeight: 1000, minWidth: 1000}}>
<GatsbyImage image={image} alt={"testimage"}/>
</div>
</BackgroundImage>
</React.Fragment>
)
}
export default GbiBridged

Modified from: https://www.gatsbyjs.com/plugins/gatsby-background-image/#gatsby-34--gatsby-plugin-image applying your code

Gatsby changed the image plugin from gatsby-image (Gatsby 1 and 2) to gatsby-plugin-image (version 3 onwards). Among other things, it has changed the internal GraphQL nodes of the image data, hence the workaround of using gatsby-background-image has also changed accordingly. In your case, you are using the deprecated version of gatsby-image so your code is not able to display the image.

You can follow the full discussion in this GitHub thread: https://github.com/timhagn/gatsby-background-image/issues/141

Cannot understand how background-image url works in Gatsby.js

Yes, this is the expected behavior for your assets in /static, read more about it in the docs: Using the Static Folder.

However, adding your images there is not a best practice because they won't be optimized with Gatsby's build time image processing and gatsby-image.

The docs also have good resources for this: Using Gatsby Image to Prevent Image Bloat, or Working with images in Gatsby.

Half-screen image with Gatsby StaticImage

You have exposed an style or imgStyle props in both: StaticImage as well as GatsbyImage.

  • style: Inline styles applied to the outer wrapper.
  • imgStyle: Inline styles applied to the <img> element.

Source: https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-plugin-image/#shared-props

Depending on how's your JSX structure you may want to use one or another but answering your question: yes, there's no need of using an external .scss file, you can use inline styles as desired:

<StaticImage
imgStyle={{ width:"300vh", height:"50vh" }}
style={{ width:"300vh", height:"50vh" }}
/>

Use whichever works better for your scenario.

React / Gatsby dynamic background images in a component

The above approach is impossible as best I can tell, but as I discovered, it's impossible for a good reason. You have to FULLY give into the React (Gatsby) way of doing things and my approach above was trying to do this from a Drupal/WordPress-CMS-build perspective.

Check out my revised component for LocationRelated:

import React from "react"
import Link from 'gatsby-link'

class LocationRelated extends React.Component {

render() {

// Setup inline style objects using ES6 template literals which pull in the correct paths from the content pages themselves
const pfbRelatedPrevBG = {
backgroundImage: `linear-gradient( to bottom, rgba(1,1,1,0.2), rgba(2,2,2,0.2) ), url(${ this.props.prevLocationImgPath.sizes.src })`
}
const pfbRelatedNextBG = {
backgroundImage: `linear-gradient( to bottom, rgba(1,1,1,0.2), rgba(2,2,2,0.2) ), url(${ this.props.nextLocationImgPath.sizes.src })`
}

return (
<div className="pfb-related-bg-container">
<aside className="pfb-related-container">
<section className="pfb-related-content">
<section className="pfb-related-image-container">
<Link
to={ this.props.prevLocationPath }
className="pfb-related-left-arrow"
>
<img src= { LeftArrow } alt="Navigate to the previous location in the PFB Annual Report" />
<div className="pfb-related-left-arrow-text">Previous</div>
</Link>
<Link
to={ this.props.prevLocationPath }
className="pfb-related-1"
style={ pfbRelatedPrevBG }
>
<p className="pfb-related-text">{ this.props.prevLocationName }</p>
</Link>
<Link
to={ this.props.nextLocationPath }
className="pfb-related-2"
style= { pfbRelatedNextBG }
>
<p className="pfb-related-text">{ this.props.nextLocationName }</p>
</Link>
<Link
to={ this.props.nextLocationPath }
className="pfb-related-right-arrow"
>
<img src= { RightArrow } alt="Navigate to the next location in the PFB Annual Report" />
<div className="pfb-related-right-arrow-text">Next</div>
</Link>
</section>
</section>
</aside>
</div>
)
}
}

export default LocationRelated

You'll notice not much is different than the above attempt but pay attention to the this.props.nextLocationImgPath.sizes.src path being used in the backgroundImage object literal. You have to pass backgroundImage the source path as a prop. Don't try to do it in the component like I was. React's separation of concerns is about getting data out of components and instead feeding data in through props.

So then the question becomes: if you have to pass the path in as a prop, how do you get the path when you call your component at the page level?

If you're using Gatsby (and you should), you need to use GraphQL to get the optimized image paths. In my example, we will call for background-image path on the same page where we would call the LocationRelated component.

Simplified example of my page that concentrates on the issue at hand:

import React from 'react'
import Img from "gatsby-image";

import LocationRelated from '../components/LocationRelated'

class CharlotteLocation extends React.Component {
render() {
return (
<div>
<LocationRelated
prevLocationName="Detroit"
prevLocationPath="detroit"
prevLocationImgPath= { this.props.data.charlottePrevImage }
nextLocationName="Montana"
nextLocationPath="montana"
nextLocationImgPath= { this.props.data.charlotteNextImage }
/>
</div>
)
}
}

export default CharlotteLocation

// GraphQL queries for each image
export const CharlotteImageQuery = graphql`
query CharlotteImageQuery {
charlottePrevImage: imageSharp(id: { regex: "/PFB_DETROIT/" }) {
sizes(maxWidth: 600 ) {
...GatsbyImageSharpSizes_withWebp
}
},
charlotteNextImage: imageSharp(id: { regex: "/PFB_MONTANA/" }) {
sizes(maxWidth: 600 ) {
...GatsbyImageSharpSizes_withWebp
}
}
}
`

These GraphQL queries make available the optimized paths to the files we need, and now we can send them into our LocationRelated component via this.props.data.

gatsby-image and GraphQL are a bit tricky to work with at first so check out this nice tutorial by Kyle Gill. It got me going a bit better than the Gatsby documentation did.

For reference, here is how I set up my gatsby-config.js in the project to get all these plugins working nicely together (I'm pulling the images from a standalone images directory in my project rather than in a component, so I needed gatsby-source-filesystem to make all this work along with gatsby-image, gatsby-transformer-sharp, gatsby-plugin-sharp,):

module.exports = {
siteMetadata: {
title: 'PFB2017 Site',
},
//pathPrefix: "/pfb2017-site",
plugins: [
// Adds in React Helmet for metadata
`gatsby-plugin-react-helmet`,

// Gives us sass in the project
`gatsby-plugin-sass`,

// This plugin transforms JSON, which is how we are storing our location data
`gatsby-transformer-json`,

// Adds in Gatsby image handling
`gatsby-image`,
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,

/**
* This is how you customize gatsby-source-filesystem
* Check this page out for more background
* https://www.gatsbyjs.org/docs/building-with-components
* By default, the gatsby-default starter kit comes with the `pages` directory wired up
* I'm adding it here for consistency but you don't need it
* What I have added into the starter are `images` and `data`, subfolders we'll need for the PFB project
*
*/

{
resolve: `gatsby-source-filesystem`,
options: {
name: `pages`,
path: `${__dirname}/src/pages`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `data`,
path: `${__dirname}/src/data`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`
}
}
],
};

Creating an Opaque / transparent gatsby-background-image

The opacity of the background image itself is set in the :before pseudoselector of your background container, so you will need to create a selector which include your background image container and accessing directly to you :before, of course, you'll need to use !important in that case... Something like:

.bgImage::before{
opacity: .03 !important;
}

You can override completely the styles by replacing the :after pseudoselector too by:

.bgImage::after{
opacity: .03 !important;
}


Related Topics



Leave a reply



Submit