Next.js: Image component isn't fluid

Created on 28 Oct 2020  路  14Comments  路  Source: vercel/next.js

Bug report

Describe the bug

The Image component wrapper has a fixed width and can't be changed.

To Reproduce

I created a codesandbox to illustrate the issue.
https://codesandbox.io/s/image-component-isnt-fluid-vsho0

This is a really common layout, images in columns. They have a final width but they should still be fluid.
If I remove the width and height props then the Image component will use the deviceSizes setting which is not ideal as those are generic.

Expected behavior

I was wondering if we could turn that fixed size off as the padding on the internal wrapper already takes care of maintaining the image ratio.

Additional context

I understand why that is there, it helps mitigate layout shifting, and I appreciate that but it's really rare when an image is fixed, 100% of the time. The web has passed that point long ago.
I also wanna start a conversation. Should the Image component use the sizes attribute and respect media queries? Using this codesandbox as an example, these images should probably be served as the following sizes="(max-width: 768px) 768px, 269px". We want a bigger image that will be 100% of the viewport and then go back to their max size.

story needs investigation

Most helpful comment

Also, maintaining just an img tag will make sure that object-fit and other css properties are respected and work as you intended.

All 14 comments

I can't really think of too many occasions when I set the exact width/height of an image in pixels rather than a percentage. On mobile for example, it's pretty common to set a header image (above the fold) to width:100%

As mentioned, If say the component width is set to 900, an inline style will be set on the image wrapper to max-width:100% width: 900px. To address this I can target the wrapper and set width:100% !important but it would be nice to have the component default to fluid.

Isn't unsized property there for bypassing width and height? :)
https://nextjs.org/docs/api-reference/next/image

Isn't unsized property there for bypassing width and height? :)
https://nextjs.org/docs/api-reference/next/image

True, that is an option but in my case the images are above the fold (banner images).

I understand why that is there, it helps mitigate layout shifting

Indeed, which is why we recommend using width and height instead of unsized.

A possible solution for a future version of next/image, is using a combination of all three (width and height and unsized) to indicate width: 100% but still maintain the aspect ratio.

There's a draft spec for CSS aspect-ratio, but we can't rely on browser support at this time, so we would need to implement a similar solution with inline styles.

I wanna go as far as to say that those two wrapping divs are completely unnecessary.
Passing the width and height to the image will make sure we avoid too much layout shift.
And if you wanna have an image that keeps its ratio but is fluid, it's as simple as this
<img src="" srcset="" width="300" height="400" style="width: 100%; height: auto" />

I think the Image component should return what the name implies, an img. The web standards will keep improving it, for example the css property aspect-ratio, different loading standards might come in the future as well. The rest is up to the developer

Also, maintaining just an img tag will make sure that object-fit and other css properties are respected and work as you intended.

@marlonmarcello Any additional properties are already passed to the underling <img> element, so you can use object-fit today.

The team discussed how to make the image "fluid" or "responsive" and we decided to introduce a new attribute for layout that allows for values such as fixed, intrinsic, or responsive.

We also are going to double down on discouraging unsized usage because the layout options will solve those use cases.

@styfle if I use object-fit today it will be relative to the wrapping div, let's say I wanted to have a full width header with a variable height of 45vh for example with a cover image that is width: 100%; height: 100%; object-fit: cover; object-position: center, the image would be relative to the wrapping div and not my header whereas with just an img tag, that would work as intended.

With the fear of sounding like a jerk I would ask you if you mind explaining the reasoning behind the need for two wrapping divs?

We can probably use a single <div> wrapper instead of two. The second one can be a sibling to the <img> to ensure the aspect ratio is correct.

We can probably use a single <div> wrapper instead of two. The second one can be a sibling to the <img> to ensure the aspect ratio is correct.

The PR looks good though, it seems to accommodate the problems with the root wrapper. I just tried it out and it's working on my end :partying_face:

Are these changes already on canary version?

Are these changes already on canary version?

They are now

There are still some minor issues about this, at least for us! Please check this link and let me know if some of you encounter same problem!

Was this page helpful?
0 / 5 - 0 ratings