gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.26k stars 10.3k forks source link

[gatsby-image] Using `fluid` images on a flexbox layout when the images should have a max width. #12818

Closed SammyIsra closed 5 years ago

SammyIsra commented 5 years ago

Summary

fluid images seem to have no width or height on a flexbox display.

Relevant information

I've tried using fixed images as well, but these images need to shrink when the width of the display is smaller.

A demonstration can be seen here: https://deploy-preview-10--optimistic-goodall-a71eb1.netlify.com/photographer right under the description, there is a flexbox display of images where all the images are too small to be seen.

The code for where I use gatsby-image is here: https://github.com/SammyIsra/SammyPortfoliov2/blob/1d26c04a049eed718b866baa51870523837e9e68/src/pages/photographer.js#L117

Environment (if relevant)

  System:
    OS: Windows 10
    CPU: (4) x64 Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz
  Binaries:
    Yarn: 1.13.0 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 6.4.1 - ~\AppData\Roaming\npm\npm.CMD
  Browsers:
    Edge: 42.17134.1.0
  npmPackages:
    gatsby: 2.2.6 => 2.2.6
    gatsby-image: ^2.0.34 => 2.0.34
    gatsby-plugin-react-helmet: ^3.0.8 => 3.0.8
    gatsby-plugin-remote-images: 1.0.1 => 1.0.1
    gatsby-plugin-sharp: 2.0.30 => 2.0.30
    gatsby-plugin-styled-components: ^3.0.6 => 3.0.6
    gatsby-plugin-typography: ^2.2.8 => 2.2.8
    gatsby-source-filesystem: 2.0.23 => 2.0.23
    gatsby-transformer-remark: ^2.3.1 => 2.3.1
    gatsby-transformer-sharp: ^2.1.17 => 2.1.17

Also: Mozilla Firefox v65

File contents (if changed)

gatsby-config.js:

const path = require("path");

module.exports = {
  siteMetadata: {
    title: "Sammy is a...",
    description:
      "☄️Sammy's website and portfolio!\nFrom Development to Photography",
    tags: ["portfolio", "software developer", "developer", "photographer"]
  },
  plugins: [
    "gatsby-plugin-react-helmet",
    "gatsby-plugin-styled-components",
    {
      resolve: "gatsby-plugin-typography",
      options: {
        pathToConfigModule: path.join(__dirname, "src", "typography.js")
      }
    },
    {
      resolve: "gatsby-source-filesystem",
      options: {
        name: "posts",
        path: `${__dirname}/src/posts`
      }
    },
    "gatsby-transformer-remark",
    {
      resolve: "gatsby-plugin-remote-images",
      options: {
        nodeType: "flickrImage",
        imagePath: "url_l" // Use the 'large' sized image for the pictures in the photostream
      }
    },
    "gatsby-transformer-sharp",
    "gatsby-plugin-sharp"
  ]
};

package.json:

  "name": "gatsby-starter-hello-world",
  "private": true,
  "description": "A simplified bare-bones starter for Gatsby",
  "version": "0.1.0",
  "license": "MIT",
  "scripts": {
    "build": "gatsby build",
    "develop": "gatsby develop",
    "format": "prettier --write src/**/*.{js,jsx}",
    "start": "npm run develop",
    "serve": "gatsby serve",
    "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\"",
    "deploy-demo": "gatsby build&&surge ./public/ --domain sammyis-gdemo.surge.sh"
  },
  "dependencies": {
    "babel-plugin-styled-components": "^1.10.0",
    "gatsby": "2.2.6",
    "gatsby-image": "^2.0.34",
    "gatsby-plugin-react-helmet": "^3.0.8",
    "gatsby-plugin-remote-images": "1.0.1",
    "gatsby-plugin-sharp": "2.0.30",
    "gatsby-plugin-styled-components": "^3.0.6",
    "gatsby-plugin-typography": "^2.2.8",
    "gatsby-source-filesystem": "2.0.23",
    "gatsby-transformer-remark": "^2.3.1",
    "gatsby-transformer-sharp": "^2.1.17",
    "graphql": "^14.1.1",
    "node-fetch": "^2.3.0",
    "react": "^16.8.4",
    "react-dom": "^16.8.4",
    "react-helmet": "^5.2.0",
    "react-masonry-component": "6.2.1",
    "react-typography": "^0.16.19",
    "styled-components": "^4.1.3",
    "typography": "^0.16.19",
    "typography-theme-fairy-gates": "^0.16.19"
  },
  "devDependencies": {
    "prettier": "^1.16.4"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/gatsbyjs/gatsby-starter-hello-world"
  },
  "bugs": {
    "url": "https://github.com/gatsbyjs/gatsby/issues"
  }
}

gatsby-node.js:

const { createFilePath } = require("gatsby-source-filesystem");
const path = require("path");
const fetch = require("node-fetch");

const urlAllPhotos =
  "https://us-central1-photo-flick-d764c.cloudfunctions.net/getFlickPhotos?sortBy=date&limitTo=40";

/**
 * Fetch data from my personal Flickr endpoint to get the pictures
 */
exports.sourceNodes = function({ actions, createContentDigest }) {
  const { createNode } = actions;

  return new Promise((resolve, reject) => {
    //All photos
    fetch(urlAllPhotos)
      .then(resp => resp.json())
      .then(photos => {
        photos.forEach(element => {
          createNode(processFlickrImageList(element, createContentDigest));
        });
        resolve();
      })
      .catch(reject);
  });

  function processFlickrImageList(flickrItem, digest) {
    // console.log("Flickr:", flickrItem);
    return {
      ...flickrItem,
      address: `https://www.flickr.com/photos/${flickrItem.owner}/${
        flickrItem.id
      }/`,
      children: [],
      parent: null,
      internal: {
        type: "flickrImage",
        content: JSON.stringify(flickrItem),
        contentDigest: digest(flickrItem)
      }
    };
  }
};

exports.onCreateNode = function({ node, getNode, actions }) {
  const { createNodeField } = actions;
  if (node.internal.type === "MarkdownRemark") {
    const slug = createFilePath({ node, getNode, basePath: "pages" });
    createNodeField({
      node,
      name: "slug",
      value: `/posts${slug}`
    });
  }
};

exports.createPages = function({ graphql, actions }) {
  return new Promise((resolve, reject) => {
    const { createPage } = actions;

    graphql(`
      {
        allMarkdownRemark {
          edges {
            node {
              fields {
                slug
              }
            }
          }
        }
      }
    `)
      .then(result => {
        result.data.allMarkdownRemark.edges.forEach(({ node }) =>
          createPage({
            path: node.fields.slug,
            component: path.resolve("./src/templates/blog-post.js"),
            context: {
              slug: node.fields.slug
            }
          })
        );
        resolve();
      })
      .catch(error => {
        console.error("Error on createPages", error);
        reject(error);
      });
  });
};

gatsby-browser.js: N/A gatsby-ssr.js: N/A

wardpeet commented 5 years ago

does it work when switching fluid={sharpPhoto.childImageSharp.fixed} into fluid={sharpPhoto.childImageSharp.fluid} we use something called flex embed to make sure we keep ratio in tact

image

padding-bottom is nan because you're using fixed instead of fluid.

SammyIsra commented 5 years ago

That does help in that the images seen in the page inspector no longer have a width or height of 0px, and the padding-bottom is no longer NaN: image

However, the images still do not show, visible here: https://deploy-preview-10--optimistic-goodall-a71eb1.netlify.com/photographer (same link as before)

zpthree commented 5 years ago

Any solutions to this? I'm having the same problem.

polarathene commented 5 years ago

Well, for one you're wrapping the images in an anchor tag element, and making them inline-block. I can't recall specifics but just using a block instead of inline-block appears to fix the issue. Presumably because width/height isn't defined for the inline-block(anchor tag), so if it's width is 0px, then 100% of that for any elements within(the gatsby image), that's correct?, alternatively specify a width value for the anchor element and it'll also work.

If you don't want to use a fixed value since you're using flex in the parent element as display, set a child to something like flex: 1; or flex-grow: 1 etc.

spwisner commented 5 years ago

The solution that worked for me was wrapping each anchor tag in a div which is assigned a width of 100%: Then, flexbox is applied to the div instead of the anchor tag:

import Img from 'gatsby-image'

const ImgGallery = ({ data }) => (
  <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
    <div style={{ width: '100%' }}>
        <a href='#'>
            <Img fluid={data.fluidImageOne.childImageSharp.fluid} />
        </a>
    </div>
    <div style={{ width: '100%' }}>
        <a href='#'>
            <Img fluid={data.fluidImageTwo.childImageSharp.fluid} />
        </a>
    </div>
    <div style={{ width: '100%' }}>
        <a href='#'>
            <Img fluid={data.fluidImageThree.childImageSharp.fluid} />
        </a>
    </div>
  </div>
)
wardpeet commented 5 years ago

I looked properly at your code @SammyIsra sadly what you want isn't really feasible as you want it. Fluid will always keep it's ratio so you probably want to move into a masonry view. Or go for fixed and keep it centered.

SammyIsra commented 5 years ago

I think that makes sense. In any case, I switched the style of what I was trying to do, thank you!

MTyson commented 4 years ago

using fixed worked for my case, but I'm not sure WHY exactly :P

araphiel commented 4 years ago

In case this helps, check if your CSS has any unscoped instances of position: relative.

Something like this will easily break gatsby-image:

* {
 position: relative;
}
eerrecalde commented 4 years ago

Just in case someone's looking for a way to restrict the image size to max its original size (Not sure if it's the best approach, but it worked to me). In the query, you might want to add the original img size like this:

query {
      logoImg: file(relativePath: { eq: "logo.png" }) {
        childImageSharp {
          fluid(maxWidth: 300) {
            ...GatsbyImageSharpFluid
          }
          original {
            width
          }
        }
      }
    }

And then you can just use it in the element wrapping the image to set its width

KoolP commented 3 years ago

Set the parent that wraps the image to flexGrow: 1 Here a material UI example:

imageGrid: {
    flexGrow: 1,
}

<Grid item sm={6} className={classes.imageGrid}>
          <Img fluid={mainImage.fluid} alt="Cruise ship" />
 </Grid>