1

What I want to achive

I am using gatsby and want to design an image gallery. Clicking on one of the images shall open a modal, which: (1) is showing the image in maximum possible size, so that it still fits into the screen and (2) is centered in the screen.

My Code

/* imagemodal.js */
import React from 'react'
import * as ImagemodalStyles from './imagemodal.module.css'
import { Modal } from 'react-bootstrap'
import Img from 'gatsby-image'
import { useStaticQuery, graphql } from 'gatsby'

export default function Imagemodal() {
  const data = useStaticQuery(graphql`
    query {
      file(relativePath: { eq: "images/mytestimage.jpg" }) {
        childImageSharp {
          fluid(maxWidth: 1200) {
            ...GatsbyImageSharpFluid
          }
        }
      }
    }
  `)

  return (
    <div>
      <Modal
        show={true}
        centered
        className={ImagemodalStyles.imageModal}
        dialogClassName={ImagemodalStyles.imageModalDialog}
        onHide={(e) => console.log(e)}
      >
        <Modal.Header closeButton />
        <Modal.Body className={ImagemodalStyles.imageModalBody}>
          <h1>TestInhalt</h1>
          <Img fluid={data.file.childImageSharp.fluid} />
        </Modal.Body>
      </Modal>
    </div>
  )
}


/* imagemodal.module.scss */
.imageModalDialog {
  display: inline-block;
  width: auto;
}
.imageModal {
  text-align: center;
}
.imageModalBody img {
  max-height: calc(100vh - 225px);
}

The Problem

The image does not scale to the screen size. The image is either too big - so it flows over the vieport - or it is too small. Secondly, the modal size does not respond to the image size correctly and / or is not centered.

What I tried

  • I used this suggestion for the CSS: How to limit the height of the modal?
  • I tried as well dozens of other CSS parameter combinations. But I could not find a working solution.
  • I tried to format the gatsby-image directly with a style-tag.
  • I tried as well react-modal but had similar problems.

Does anyone have a good solution to show a gatsby-image in full screen size in a responsive modal? For me it is okay to use either the bootstrap-modal or react-modal - or any other suitable solution.


Edit

In the end I ended up with a workaround. I used react-image-lightbox and took the Image-Source from gatsby-image as the input for lightbox. My component gets the data from the graphQL query in the props via props.imageData. This works quite well for me:

import Lightbox from 'react-image-lightbox';
...

export default function Imagegallery(props) {
  ...
  const allImages = props.imageData.edges
  const [indexImageToShow, setIndexImageToShow] = useState()
  ...
  return(
  <Lightbox
    mainSrc={allImages[indexImageToShow].node.childrenImageSharp[0].fluid.src}
    ...
  />

Special thanks to @FerranBuireu to point me to the right direction

somecoder
  • 53
  • 6
  • Can you provide a working CodeSandbox? – Ferran Buireu Mar 04 '21 at 09:52
  • @FerranBuireu: unfortunately on CodeSandbox not even the official "gatsby-starter-default" template is running (due to some node.js and gatsby version conflicts), so I could not get that running. Sorry!! But I have set up a git repo with a fully working example. Hope that helps: https://github.com/codingexamples/imagemodaltest – somecoder Mar 04 '21 at 13:21

1 Answers1

0

Assuming that the functionality works as expected, as it seems, it's a matter of CSS rules, not React/Gatsby issue. The following rule:

.imageModalBody img {
  max-height: calc(100vh - 225px);
}

It Will never be applied properly, since gatsby-image creates an output of HTML structure of nested <div>, <picture> and <img> so your rule will be affected by the inherited and relativity of the HTML structure. In other words, you are not pointing to the image itself with that rule because of the result HTML structure.

You should point to the <Img>, which indeed, it's a wrapper, not an <img>.

  return (  
    <div>
      <Modal show={true} onHide={handleClose} centered className={ImagemodalStyles.imageModal} dialogClassName={ImagemodalStyles.imageModalDialog}>
        <Modal.Header closeButton />
        <Modal.Body>
          <Img className={ImagemodalStyles.imageModalBody} fluid={props.data.file.childImageSharp.fluid} />
        </Modal.Body>
      </Modal>
    </div>
  )

The snippet above will add the (spot the difference, without img):

.imageModalBody {
  max-height: calc(100vh - 225px);
}

To the wrapper, which may or may not fix the issue, but at least will apply the rule correctly. It's difficult to know what's wrong without a CodeSandbox but you will apply the styles correctly with this workaround.

Keep always in mind that when using gatsby-image, the <img> it's profound in the resultant HTML structure so your styles should apply to the outer wrapper of it.

Ferran Buireu
  • 28,630
  • 6
  • 39
  • 67
  • Thank you for your super fast answer! The CSS hint is very cool. Unfortunately after trying it out, it has the same behaviour :( – somecoder Mar 04 '21 at 13:24
  • Yes, I can't guess the output only with a few code. I can't provide a copy/paste solution with the information provided. The idea is to point you in the right direction. You need to know how `gatsby-image` wraps your image in a series of nested `
    ` so your CSS rules may be applied differently. In the end, it's a matter of styles so the modal that contains the wrapper of the image should be placed relative to the wrapper.
    – Ferran Buireu Mar 04 '21 at 13:44
  • 1
    Thanx a lot. Really cool community around gatsby!! – somecoder Mar 04 '21 at 14:00
  • Make some trial, try to extend your question with new examples, or add a Codesandbox. The workaround to fix it relies on the CSS rules that apply, as well as to your model and the outer wrapper of the `gatsby-image` – Ferran Buireu Mar 04 '21 at 14:14
  • I will get back, as soon as I have a solution – somecoder Mar 04 '21 at 14:19