admin管理员组

文章数量:1334393

Live example (images might load slowly):

I'm making a photography site with GatsbyJS and using the following template as a base site that I've been changing:

Being really new to graphql I've run into a problem displaying images after a user clicks on the card to show the 'Portraits' subpage. The images are all displayed with a fixed width and height which I don't want. I need to display them with their native width and height, just resized to fit into the grid.

I've tried changing the graphql query in the project.js file, where you set the maxWidth: 1600 to no avail, as well as the resize(width: 800) further down the query. Later I found out that changing the margin on gatsby-image-wrapper through dev tools gave me the expected results, but that required changing the core gatsby-image plugin and having to manually change the margin for every image separately which isn't the solution.

project.js

import React from 'react'
import Img from 'gatsby-image'
import PropTypes from 'prop-types'
import { graphql } from 'gatsby'
import styled from 'styled-ponents'

import { Layout, ProjectHeader, ProjectPagination, SEO } from '../ponents'
import config from '../../config/site'

const BG = styled.div`
  background-color: ${props => props.theme.colors.bg};
  position: relative;
  padding: 2rem 0 0 0;
`

const OuterWrapper = styled.div`
  padding: 0 ${props => props.theme.contentPadding};
  margin: -10rem auto 0 auto;
`

const InnerWrapper = styled.div`
  position: relative;
  max-width: ${props => `${props.theme.maxWidths.project}px`};
  margin: 0 auto;
`

const Grid = styled.div`
  display: grid;
  grid-template-columns: repeat(${props => props.theme.gridColumnsProject}, 1fr);
  grid-gap: 20px;

  @media (max-width: 768px) {
    grid-template-columns: 1fr;
  }
`

const Project = ({ pageContext: { slug, prev, next }, data: { project: postNode, images } }) => {
  const project = postNode.frontmatter

  return (
    <Layout customSEO>
      <SEO postPath={slug} postNode={postNode} postSEO />
      <ProjectHeader
        name={config.name}
        date={project.date}
        title={project.title}
        areas={project.areas}
        text={postNode.body}
      />
      <BG>
        <OuterWrapper>
          <InnerWrapper>
            <Grid>
              {images.nodes.map(image => (
                <Img
                  alt={image.name}
                  key={image.childImageSharp.fluid.src}
                  fluid={image.childImageSharp.fluid}
                  style={{ margin: '2rem 0' }}
                />
              ))}
            </Grid>
          </InnerWrapper>
          <ProjectPagination next={next} prev={prev} />
        </OuterWrapper>
      </BG>
    </Layout>
  )
}

export default Project

Project.propTypes = {
  pageContext: PropTypes.shape({
    slug: PropTypes.string.isRequired,
    next: PropTypes.object,
    prev: PropTypes.object,
  }),
  data: PropTypes.shape({
    project: PropTypes.object.isRequired,
    images: PropTypes.object.isRequired,
  }).isRequired,
}

Project.defaultProps = {
  pageContext: PropTypes.shape({
    next: null,
    prev: null,
  }),
}

export const pageQuery = graphql`
  query($slug: String!, $absolutePathRegex: String!) {
    images: allFile(
      filter: {
        absolutePath: { regex: $absolutePathRegex }
        extension: { regex: "/(jpg)|(png)|(tif)|(tiff)|(webp)|(jpeg)/" }
      }
      sort: { fields: name, order: ASC }
    ) {
      nodes {
        name
        childImageSharp {
          fluid(maxWidth: 1600, quality: 90) {
            ...GatsbyImageSharpFluid_withWebp
          }
        }
      }
    }
    project: mdx(fields: { slug: { eq: $slug } }) {
      body
      excerpt
      parent {
        ... on File {
          mtime
          birthtime
        }
      }
      frontmatter {
        cover {
          childImageSharp {
            resize(width: 800) {
              src
            }
          }
        }
        date(formatString: "DD.MM.YYYY")
        title
        areas
      }
    }
  }
`

Card.js the parent ponent:

import React from 'react'
import styled from 'styled-ponents'
import PropTypes from 'prop-types'
import { useSpring, animated, config } from 'react-spring'
import { rgba } from 'polished'
import Img from 'gatsby-image'
import { Link } from 'gatsby'

const CardItem = styled(Link)`
  min-height: 500px;
  position: relative;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3), 0 15px 12px rgba(0, 0, 0, 0.2);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  color: ${props => props.theme.colors.color};
  transition: all 0.3s ease-in-out;

  &:hover {
    color: white;
    transform: translateY(-6px);
  }

  @media (max-width: ${props => props.theme.breakpoints.s}) {
    min-height: 300px;
  }
`

const Cover = styled.div`
  width: 100%;
  height: 100%;
  position: absolute;
`

const Content = styled.div`
  padding: 1rem;
  position: relative;
  transition: all 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
  opacity: 0;
  background: ${props => rgba(props.theme.colors.link, 0.65)};
  height: 0;

  ${CardItem}:hover & {
    opacity: 1;
    height: 120px;
  }
`

const Bottom = styled.div`
  margin-top: 0.5rem;
  display: flex;
  align-items: center;
  font-size: 0.85rem;
  div:first-child {
    margin-right: 1rem;
  }
`

const Name = styled.h2`
  margin-bottom: 0;
  margin-top: 0;
`

const Card = ({ path, cover, date, areas, title, delay }) => {
  const springProps = useSpring({
    config: config.slow,
    delay: 200 * delay,
    from: { opacity: 0, transform: 'translate3d(0, 30px, 0)' },
    to: { opacity: 1, transform: 'translate3d(0, 0, 0)' },
  })

  return (
    <animated.div style={springProps}>
      <CardItem to={path}>
        <Cover>
          <Img fluid={cover} />
        </Cover>
        <Content>
          <Name>{title}</Name>
          <Bottom>
            <div>{date}</div>
            <div>
              {areas.map((area, index) => (
                <React.Fragment key={area}>
                  {index > 0 && ', '}
                  {area}
                </React.Fragment>
              ))}
            </div>
          </Bottom>
        </Content>
      </CardItem>
    </animated.div>
  )
}

export default Card

Card.propTypes = {
  path: PropTypes.string.isRequired,
  cover: PropTypes.object.isRequired,
  date: PropTypes.string.isRequired,
  areas: PropTypes.array.isRequired,
  title: PropTypes.string.isRequired,
  delay: PropTypes.number.isRequired,
}

I expect the images to show in their native width and height, but resized to fit the grid. Providing visual representation below on how it looks now and what the expected result is. Current result and expected result

Cheers!

Live example (images might load slowly): https://suhadolnik-photo.surge.sh/portreti

I'm making a photography site with GatsbyJS and using the following template as a base site that I've been changing: https://github./LekoArts/gatsby-starter-portfolio-emilia

Being really new to graphql I've run into a problem displaying images after a user clicks on the card to show the 'Portraits' subpage. The images are all displayed with a fixed width and height which I don't want. I need to display them with their native width and height, just resized to fit into the grid.

I've tried changing the graphql query in the project.js file, where you set the maxWidth: 1600 to no avail, as well as the resize(width: 800) further down the query. Later I found out that changing the margin on gatsby-image-wrapper through dev tools gave me the expected results, but that required changing the core gatsby-image plugin and having to manually change the margin for every image separately which isn't the solution.

project.js

import React from 'react'
import Img from 'gatsby-image'
import PropTypes from 'prop-types'
import { graphql } from 'gatsby'
import styled from 'styled-ponents'

import { Layout, ProjectHeader, ProjectPagination, SEO } from '../ponents'
import config from '../../config/site'

const BG = styled.div`
  background-color: ${props => props.theme.colors.bg};
  position: relative;
  padding: 2rem 0 0 0;
`

const OuterWrapper = styled.div`
  padding: 0 ${props => props.theme.contentPadding};
  margin: -10rem auto 0 auto;
`

const InnerWrapper = styled.div`
  position: relative;
  max-width: ${props => `${props.theme.maxWidths.project}px`};
  margin: 0 auto;
`

const Grid = styled.div`
  display: grid;
  grid-template-columns: repeat(${props => props.theme.gridColumnsProject}, 1fr);
  grid-gap: 20px;

  @media (max-width: 768px) {
    grid-template-columns: 1fr;
  }
`

const Project = ({ pageContext: { slug, prev, next }, data: { project: postNode, images } }) => {
  const project = postNode.frontmatter

  return (
    <Layout customSEO>
      <SEO postPath={slug} postNode={postNode} postSEO />
      <ProjectHeader
        name={config.name}
        date={project.date}
        title={project.title}
        areas={project.areas}
        text={postNode.body}
      />
      <BG>
        <OuterWrapper>
          <InnerWrapper>
            <Grid>
              {images.nodes.map(image => (
                <Img
                  alt={image.name}
                  key={image.childImageSharp.fluid.src}
                  fluid={image.childImageSharp.fluid}
                  style={{ margin: '2rem 0' }}
                />
              ))}
            </Grid>
          </InnerWrapper>
          <ProjectPagination next={next} prev={prev} />
        </OuterWrapper>
      </BG>
    </Layout>
  )
}

export default Project

Project.propTypes = {
  pageContext: PropTypes.shape({
    slug: PropTypes.string.isRequired,
    next: PropTypes.object,
    prev: PropTypes.object,
  }),
  data: PropTypes.shape({
    project: PropTypes.object.isRequired,
    images: PropTypes.object.isRequired,
  }).isRequired,
}

Project.defaultProps = {
  pageContext: PropTypes.shape({
    next: null,
    prev: null,
  }),
}

export const pageQuery = graphql`
  query($slug: String!, $absolutePathRegex: String!) {
    images: allFile(
      filter: {
        absolutePath: { regex: $absolutePathRegex }
        extension: { regex: "/(jpg)|(png)|(tif)|(tiff)|(webp)|(jpeg)/" }
      }
      sort: { fields: name, order: ASC }
    ) {
      nodes {
        name
        childImageSharp {
          fluid(maxWidth: 1600, quality: 90) {
            ...GatsbyImageSharpFluid_withWebp
          }
        }
      }
    }
    project: mdx(fields: { slug: { eq: $slug } }) {
      body
      excerpt
      parent {
        ... on File {
          mtime
          birthtime
        }
      }
      frontmatter {
        cover {
          childImageSharp {
            resize(width: 800) {
              src
            }
          }
        }
        date(formatString: "DD.MM.YYYY")
        title
        areas
      }
    }
  }
`

Card.js the parent ponent:

import React from 'react'
import styled from 'styled-ponents'
import PropTypes from 'prop-types'
import { useSpring, animated, config } from 'react-spring'
import { rgba } from 'polished'
import Img from 'gatsby-image'
import { Link } from 'gatsby'

const CardItem = styled(Link)`
  min-height: 500px;
  position: relative;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3), 0 15px 12px rgba(0, 0, 0, 0.2);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  color: ${props => props.theme.colors.color};
  transition: all 0.3s ease-in-out;

  &:hover {
    color: white;
    transform: translateY(-6px);
  }

  @media (max-width: ${props => props.theme.breakpoints.s}) {
    min-height: 300px;
  }
`

const Cover = styled.div`
  width: 100%;
  height: 100%;
  position: absolute;
`

const Content = styled.div`
  padding: 1rem;
  position: relative;
  transition: all 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
  opacity: 0;
  background: ${props => rgba(props.theme.colors.link, 0.65)};
  height: 0;

  ${CardItem}:hover & {
    opacity: 1;
    height: 120px;
  }
`

const Bottom = styled.div`
  margin-top: 0.5rem;
  display: flex;
  align-items: center;
  font-size: 0.85rem;
  div:first-child {
    margin-right: 1rem;
  }
`

const Name = styled.h2`
  margin-bottom: 0;
  margin-top: 0;
`

const Card = ({ path, cover, date, areas, title, delay }) => {
  const springProps = useSpring({
    config: config.slow,
    delay: 200 * delay,
    from: { opacity: 0, transform: 'translate3d(0, 30px, 0)' },
    to: { opacity: 1, transform: 'translate3d(0, 0, 0)' },
  })

  return (
    <animated.div style={springProps}>
      <CardItem to={path}>
        <Cover>
          <Img fluid={cover} />
        </Cover>
        <Content>
          <Name>{title}</Name>
          <Bottom>
            <div>{date}</div>
            <div>
              {areas.map((area, index) => (
                <React.Fragment key={area}>
                  {index > 0 && ', '}
                  {area}
                </React.Fragment>
              ))}
            </div>
          </Bottom>
        </Content>
      </CardItem>
    </animated.div>
  )
}

export default Card

Card.propTypes = {
  path: PropTypes.string.isRequired,
  cover: PropTypes.object.isRequired,
  date: PropTypes.string.isRequired,
  areas: PropTypes.array.isRequired,
  title: PropTypes.string.isRequired,
  delay: PropTypes.number.isRequired,
}

I expect the images to show in their native width and height, but resized to fit the grid. Providing visual representation below on how it looks now and what the expected result is. Current result and expected result

Cheers!

Share edited Aug 19, 2019 at 8:42 Žane asked Aug 18, 2019 at 6:47 ŽaneŽane 1494 silver badges12 bronze badges 4
  • Do you have a working example? – ksav Commented Aug 18, 2019 at 8:38
  • Best I can provide is the demo page for the template I've used: emilia.lekoarts.de – Žane Commented Aug 18, 2019 at 13:36
  • Haven't you made some changes though? – ksav Commented Aug 18, 2019 at 16:38
  • I've added a live demo: suhadolnik-photo.surge.sh/portreti – Žane Commented Aug 19, 2019 at 8:34
Add a ment  | 

1 Answer 1

Reset to default 6

Remove height:100% and position:absolute from your cover ponent on the homepage.

const Cover = styled.div`
  width: 100%;
`

Also, in case you weren't aware, you can pass style and imgStyle props to Gatsby image to change it's css.

| style            | object | Spread into the default styles of the wrapper element         |  
| imgStyle         | object | Spread into the default styles of the actual img element      |
| placeholderStyle | object | Spread into the default styles of the placeholder img element |

So in your project template you can change the object fit style like this:

<Img
  alt={image.name}
  key={image.childImageSharp.fluid.src}
  fluid={image.childImageSharp.fluid}
  imgStyle={{ objectFit: 'contain' }}
/>

本文标签: javascriptHow to display images without cropping using gatsbyimageStack Overflow