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:
- Query the image from
graphql
import
the image, get path- 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
Google Chrome "Failed Parsing Sourcemap":Css.Map (Web Essential)
Twitter Bootstrap - Fixed Layout with Scrollable Sidebar
A VS A:Link, What Is the Difference
Control Underline Position on Text-Decoration: Underline
How to Specify a CSS Shorthand for "All Elements Except the First/Last"
How to Create a Box When Mouse Over Text in Pure CSS
CSS (Transition) After a Pseudo Element - How to Transition Content That Shows on Hover
How to Compile Less/Sass Files in Visual Studio 2017+
How to Place an Image Over Another
How to Overlay a Number on Top of a Fontawesome Glyph
Twitter Bootstrap Responsive Carousel with Multiple Items
Why Is Vertical-Align:Text-Top; Not Working in CSS
Position a Div Container on the Right Side
Lining Up Labels with Radio Buttons in Bootstrap
Extending Styles with Styled-Components Not Working