Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image component sizes property does not work #18413

Closed
josepholiveira opened this issue Oct 28, 2020 · 47 comments · Fixed by #19128
Closed

Image component sizes property does not work #18413

josepholiveira opened this issue Oct 28, 2020 · 47 comments · Fixed by #19128
Assignees
Milestone

Comments

@josepholiveira
Copy link

josepholiveira commented Oct 28, 2020

Bug report

Describe the bug

When using the Image component, the sizes property doesn't work as described in the docs.

When using the Image component, the image is resized to match the container width which is size of the width attributes that we passed, or fit 100% of the viewport if the image is larger than the screen, ignoring the sizes attribute completely.

Example of code:

<Image
      width="800px"
      height="456.8px"
      sizes="(max-width: 500px) 100px"
      src="/next.png"
      alt="Next.js"
    />

To Reproduce

I created a codesandbox example with the exact problem:

  1. Go to https://codesandbox.io/s/elated-neumann-u81mr?file=/pages/index.js
  2. Resize the browser window width to be bigger than 500px to see that the image is the size of width 800px and height 456.8px
  3. Resize the browser window width to be smaller than 500px to see that the image will fit to 100% of the screen, not respecting the sizes prop that should tell the image to be 100px

Expected behavior

I expect the image to have exactly a 100px when the view port is smaller then 500px, respecting the sizes attribute.

Screenshots

Bigger viewport width
bigger-viewport

Smaller viewport width
smaller-viewport

System information

  • OS: Ubuntu 20.04
  • Browser: Chrome
  • Version of Next.js: 10.0.0
  • Version of Node.js: v12.18.3
@SelvinM
Copy link

SelvinM commented Oct 28, 2020

I think it's only supposed to work if you use the srcset attribute. Not sure though.

@josepholiveira
Copy link
Author

I think it's only supposed to work if you use the srcset attribute. Not sure though.

I thought of that too! But giving the fact that the Image component generates the srcset for you, and that the docs doesn't provide any info on that attribute I preferred to open this issue, since it would make more sense to the Image component handle that too in that case.

@ardaerzin
Copy link

I am experiencing the same.

@SelvinM but the next/image already creates srcset

@mrmcc3
Copy link

mrmcc3 commented Oct 29, 2020

sizes - Defines what proportion of the screen you expect the image to take up. Recommended, as it helps serve the correct sized image to each device.

It's the intended size of the image so the browser can pick the best image from srcSet. From what I can tell it won't actually style the image to be that size you've got to do that manually

@Mistwell
Copy link

Also have triuble with size usage and auto srcset generated.
have image with 2806px width but component cut size to 1200px

<Image src="/images/mainpage/shadow.png" alt={''} width={2806} height={2808} quality={100} sizes={???} />

Без названия

@josepholiveira
Copy link
Author

sizes - Defines what proportion of the screen you expect the image to take up. Recommended, as it helps serve the correct sized image to each device.

It's the intended size of the image so the browser can pick the best image from srcSet. From what I can tell it won't actually style the image to be that size you've got to do that manually

Makes a lot of sense, but still a little bit weird because the Image component creates a wrapper div with some element styles, and also styles the img with some element styles that makes it hard to style the image without using !important all over the place. But with the use of the sizes and the srcset attribute it indeed should make the image the size informed, you can see a little bit of that on https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images.

@Timer Timer added this to the iteration 11 milestone Oct 29, 2020
@mrmcc3
Copy link

mrmcc3 commented Oct 29, 2020

@josepholiveira Yep you're right with an unstyled raw image tag the sizes attr does control the width. I agree the wrapper divs + default styles do put you in a situation where you can't just drop in the new Image component without adding some extra styles.

@Mistwell The Image component generates a srcset based off the default device sizes. You can override the defaults if you want to allow the browser to choose images wider then 1200. (unrelated to sizes)

@Timer Timer added the point: 2 label Oct 30, 2020
@Timer Timer modified the milestones: iteration 11, iteration 12 Oct 30, 2020
@LauraBeatris
Copy link
Contributor

LauraBeatris commented Nov 4, 2020

I had the same issue but for now, as a workaround, I'm using the layout fill property with a container and media queries

<div className="md:h-20 md:w-20 w-10 h-10 relative">
  <Image
    quality={100}
    title="Floripa+"
    src="/images/logo.png"
    alt="Floripa Mais Logo"
    loading="eager"
    layout="fill"
   />
 </div>

In that way, the image won't shift the content and always respect the size of the container. Therefore, I would prefer to use the sizes property

@LauraBeatris
Copy link
Contributor

LauraBeatris commented Nov 4, 2020

As @mrmcc3 said

Next applies a list of device width breakpoints by default which is used to handle the cases where the images are wider than the viewport.

module.exports = {
  images: {
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
  },
}

For instance:

  • Viewport: 1200px
  • Image: 1920px

The final length of this image will be smaller than 1200px in order to fit the viewport

Refer to the intrinsic image layout, which is the default one:

If intrinsic, the image will scale the dimensions down for smaller viewports but maintain the original dimensions for larger viewports.

But if you want it to be fixed, regardless of device sizes or image sizes, the fixed property is the way to go:

If fixed, the image dimensions will not change as the viewport changes (no responsiveness).

@styfle
Copy link
Member

styfle commented Nov 13, 2020

Next.js doesn't do any manipulation to the sizes property.

It is passed directly to the underlying img element, so that's why the docs link to MDN.

The thing to remember is that sizes depends on srcset, and srcset is derived from deviceSizes in your next.config.js file. So make sure the width exists there.

Also, PR #19128 is going to autogenerate sizes when the prop is omitted to remain compliant.

@kodiakhq kodiakhq bot closed this as completed in #19128 Nov 13, 2020
kodiakhq bot pushed a commit that referenced this issue Nov 13, 2020
@AshConnolly
Copy link

Can we get this re-opened? If I've understood correctly, I don't believe this is resolved.

The image component is incredible and a brilliant idea, but it seems responsive images are not behaving as expected.

When comparing @josepholiveira's example here -

https://codesandbox.io/s/elated-neumann-u81mr?file=/pages/index.js

Expected behavior: I expect the image to have exactly a 100px when the view port is smaller then 500px, respecting the sizes attribute.

Actual behavior: Resize the browser window width to be smaller than 500px to see that the image will fit to 100% of the screen, not respecting the sizes prop that should tell the image to be 100px

To a pure html example, they should behave the same shouldn't they?

Heres a codesandbox with both a next.js and html example side by side, trying to load the same size responsive images -
https://codesandbox.io/s/empty-morning-4gdp9?file=/pages/index.js

export default function IndexPage() {
  return (
    <div>
      <Image
        width="1000"
        height="571"
        sizes="(max-width: 500px) 100px, (max-width: 1023px) 400px, 1000px"
        src="https://i.imgur.com/3QPVI5K.png"
        alt="Next.js"
      />
      <img
        srcSet="https://i.imgur.com/CLjcs9D.png 100w,
        https://i.imgur.com/8Jqeo06.png 400w, 
        https://i.imgur.com/3QPVI5K.png 1000w"
        sizes="(max-width: 500px) 100px, (max-width: 1023px) 400px, 1000px"
        src="https://i.imgur.com/3QPVI5K.png"
        alt="Next.js"
      />
    </div>
  );
}

The html example is inline with the way the expected behavior quoted above by @josepholiveira, in that it is supplying a 100px image.

The Next.js example loads a 320px image (as seen in network tab), and ignores the sizes request of a 100px image. (I'm also not sure why its 320, as that value is not present in deviceSizes or imageSizes).

I know when using layout="responsive" next.js automatically supplies images that are sized based on the viewport, those images are at the following sizes: 640, 750, 828, 1080, 1200, 1920, 2048, 3840..

But is this ignoring of a requested size in the sizes prop intentional? Why could the image component not supply a 100px sized image? Loading a 320px image, that is 3.2x bigger than needed feels like a big hit to performance.

Maybe I am misunderstanding how responsive images or how the image component works, apologies if so.
Thanks again for the great work! 😃

@AshConnolly
Copy link

AshConnolly commented Jan 10, 2021

Here is another example of the sizes attribute not being used as expected -
https://codesandbox.io/s/restless-thunder-m8b9u?file=/pages/index.js

export default function IndexPage() {
  return (
    <div>
      <div className="pic-wrap">
        <Image
          src="https://i.imgur.com/zrJVdrt.jpg"
          alt="Next.js"
          width="140"
          height="210"
          sizes="(min-width: 1024px) 140px, (min-width: 475px) 110px, 82px"
          layout="responsive"
        />
      </div>
      <style jsx>{`
        img {
          width: 100%;
        }
        .pic-wrap {
          width: 82px;
        }
        @media (min-width: 475px) {
          .pic-wrap {
            width: 110px;
          }
        }
        @media (min-width: 1024px) {
          .pic-wrap {
            width: 140px;
          }
        }
      `}</style>
    </div>
  );
}

I am requesting an image that is

  • 82px on mobile
  • then 110px if viewport is 475px or wider
  • then 140px is viewport is 1024px or wider

The biggest I would want is 140px wide image. Next.js image component is supplying a 320px (28kb) image, for all sizes. That is vastly bigger than needed.

It also supplies a 640px when requesting a 82px wide image if i use layout="intrinsic":
https://codesandbox.io/s/sweet-sanderson-fu2p0?file=/pages/index.js
(sometimes its 320px instead of 640px, not sure why it seems to change)

<Image
  src="https://i.imgur.com/zrJVdrt.jpg" 
  alt="Next.js"
  width="82"
  height="123"
  layout="intrinsic"
/> 

Why is this happening? A 640px image is vastly larger than an 82px wide image and will massively degrade performance.

Again, apologies if I am misunderstanding how responsive images or how the image component works.

@cadekynaston
Copy link

@AshConnolly I've been dealing with a similar issue and I think I've figured some of this out. It's what @styfle said above.

Basically the smallest image that Next generates by default is 640px. To allow Next to generate smaller images than 640px you need to create a next.config.js file at the root of your project and specify smaller device sizes. The code in your next config file should look like this in your case:

module.exports = {
  images: {
    deviceSizes: [82, 110, 140, 640, 750, 828, 1080, 1200, 1920, 2048, 3840],
  },
};

Everything after the specific sizes you are looking for are the Next defaults.

Now you will have an image generated for each of those device widths. The sizes prop on the <Image /> are where you can override which viewport width will use which image source size which you have done. I think your code should just work as intended with those new device sizes.

@AshConnolly
Copy link

Thanks for replying @cadekynaston! Appreciate it mate! 😃

That does seem to work, but it shouldn't be needed as next already has an imageSize array by default, and it contains images that are much smaller than the 320px that is being loaded -

module.exports = {
  images: {
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
  },
}

this is taken from - https://nextjs.org/docs/basic-features/image-optimization#image-sizes

You can specify a list of image widths using the imageSizes property. These widths should be different (usually smaller) than the widths defined in deviceSizes because the arrays will be concatenated. These widths are used when the next/image component uses layout="fixed" or layout="intrinsic".

So it seems that next might not always be using this imageSizes array, and not be concatenating it with deviceSizes as explained.

@styfle are you aware of this issue?

Cheers! 👍

@cadekynaston
Copy link

You're welcome @AshConnolly! Yea I thought the same thing. Couldn't get it to work with the imageSizes array at all.

@styfle
Copy link
Member

styfle commented Jan 12, 2021

These widths are used when the next/image component uses layout="fixed" or layout="intrinsic".

This is because imageSizes is only used when generating the 1x/2x/3x srcSet for layout="fixed" or layout="intrinsic".

The deviceSizes are used for layout="responsive" and layout="fill" which generates a srcSet with all the device sizes.

https://nextjs.org/docs/api-reference/next/image#sizes

@AshConnolly
Copy link

Thanks for getting back @styfle! 😃

Interesting... so adding more sizes to deviceSizes should solve my layout="responsive" issue. Ty & ty @cadekynaston!

As for my 2nd issue above with layout="intrinsic"...

This is because imageSizes is only used when generating the 1x/2x/3x srcSet for layout="fixed" or layout="intrinsic".

Why is srcSet used for non-responsive images? Also imageSizes contains values much smaller than 320px, but I keep getting a 320px image returned when requesting a small image (sandbox example in my previous comment is 82px wide).

Am I to believe that if i want to load a small, non responsive, image that is 48px wide (smaller than 320px which is often returned), I need to use layout="intrinsic", and pass it a sizes prop (which becomes srcSet for responsive images), even though the image does not need to be responsive?

That seems confusing and it doesn't seem to work - https://codesandbox.io/s/billowing-bush-n3m0n?file=/pages/index.js

      <Image
        src="https://i.imgur.com/zrJVdrt.jpg"
        alt="Next.js"
        width="48"
        height="72"
        sizes="(min-width: 1024px) 48px, (min-width: 475px) 32px, 16px"
        layout="intrinsic"
      />

It still loads a 320px image:
Screenshot 2021-01-12 at 20 12 56

So how would I go about getting the image component to return a small, non responsive image, at (for example) 48px width? As currently it keeps returning a 320px image.

@styfle
Copy link
Member

styfle commented Jan 12, 2021

You shouldn't use sizes for layout=intrinsic.

The reason why layout=intrinsic has a srcset is for high DPI (retina) displays.

If you inspect the DOM or html response, you can see the srcset output.

Read more about srcset and sizes on MDN.

@AshConnolly
Copy link

AshConnolly commented Jan 13, 2021

Thanks for replying @styfle.

You shouldn't use sizes for layout=intrinsic.

Cool! I thought that seemed odd.

Unfortunately my issue is still present.

Can you clarify how would I go about getting the image component to return a small, non responsive image, at (for example) 82px width?

As seen here - https://codesandbox.io/s/sweet-sanderson-fu2p0?file=/pages/index.js

      <Image
        src="https://i.imgur.com/zrJVdrt.jpg"
        alt="Next.js"
        width="82"
        height="123"
        layout="intrinsic"
      />

The component is returning a 320px wide image when asking for a 82px wide image. generated html:

<img alt="Next.js" layout="intrinsic"
    data-src="/_next/image?url=https%3A%2F%2Fi.imgur.com%2FzrJVdrt.jpg&amp;w=320&amp;q=75"
    data-srcset="/_next/image?url=https%3A%2F%2Fi.imgur.com%2FzrJVdrt.jpg&amp;w=320&amp;q=75 320w"
    style="visibility: visible; height: 100%; left: 0px; position: absolute; top: 0px; width: 100%;"
    src="/_next/image?url=https%3A%2F%2Fi.imgur.com%2FzrJVdrt.jpg&amp;w=320&amp;q=75"
    srcset="/_next/image?url=https%3A%2F%2Fi.imgur.com%2FzrJVdrt.jpg&amp;w=320&amp;q=75 320w">

320px isn't even listed in imageSizes:[16, 32, 48, 64, 96, 128, 256, 384]. It's not in deviceSizes either, so I'm not sure where this value is coming from.

I'd expect the component to return a 96px wide image as that is the closest larger value in imageSizes.

On mobile devices with a 2x pixel density, if the component takes that into account (does it?), I'd expect a 256px image (the closest larger value, when the width is doubled for 2x pixel density).

If you could clarify how to do this, I'd appreciate it! 😃

@AshConnolly
Copy link

Hi @styfle! Thanks for replying! 😃
Oh i see, codesandbox was loading next 10.0.0, which was released 27 Oct 2020, and the image component has since been updated! Thanks mate, appreciate it! 👍

@DoctorDerek
Copy link

DoctorDerek commented Feb 9, 2021

Thanks to @josepholiveira @styfle @AshConnolly & @LauraBeatris for your contributions here.

I finally understand how to use the sizes prop with Next.js. Here's the simple explanation.

Can I add this to the docs via a separate pull request?

----------------------
----------------------
----------------------

Need a smaller size? Just specify a smaller visual width. The default is 100vw, meaning 100% of the viewport. For a 3-column layout, try 33vw -- the closest image to 33% of the viewport will get served. You can also use media queries to get specific with your responsive image sizes. Don't forget to add additional deviceSizes in next.config.js if you need sizes <640px for mobile devices. Otherwise, 640px will be the smallest size Next.js can serve. For convenience, you can specify a custom deviceSizes by simply adding the default imageSizes array (which goes down to 16px) before the default deviceSizes.

                module.exports = {
                images: {
                  imageSizes: [],
                  deviceSizes: [16, 32, 48, 64, 96, 128, 256, 384, 512, 640, 750, 828, 1080, 1200, 1920, 2048, 3840],
                },}

Once you add that code, you can conveniently use any small vw value (like 10vw) and know that there will always be an appropriate version on tiny mobile devices. The smallest served will be 16px, and you'll have a total of 17 responsive image sizes served automatically by Next.js v10 or later.

----------------------
----------------------
----------------------

And here's a bunch more info in case anyone finds this issue while searching online like I did.

Here's an example that can be used with this Next.js + Tailwind CSS starter blog https://jamstackthemes.dev/theme/nextjs-tailwind-starter-blog

That starter blog has a nice overview of using Images in Next.js 10 here: https://tailwind-nextjs-starter-blog.vercel.app/blog/guide-to-using-images-in-nextjs

Unfortunately it's not clear what to do with a layout="fill" image that won't fill the entire viewport, without reading the MDN docs several dozen times.

(This obvious "use a sizes value of 33vw for an image in a 3-column grid" example does not appear in the MDN docs.)

Here's a basic example of a small responsive image using 33vw (33% of the visual width of the device's viewport):

index.js

          <div>
            <div className="relative h-36">
              <Image
                src="/static/images/ocean.jpeg"
                className="object-cover rounded-full"
                layout="fill"
                sizes="33vw"
              />
            </div>
          </div>

Here's a full 3-column gird layout example that also has a long description of how you can use media queries in the string you pass as the "sizes" prop:

index.js

      <div className="max-w-3xl px-4 mx-auto sm:px-6 xl:max-w-5xl xl:px-0">
        <div className="grid grid-cols-3 gap-1 text-center md:gap-2 xl:gap-3">
          <div>
            <div className="relative h-36">
              <Image
                src="/static/images/ocean.jpeg"
                className="object-cover rounded-full"
                layout="fill"
                sizes="(min-width: 768px) 256px, (min-width: 1024px) 384px, 128px" // 128px used if width < 768px

                // Tailwind CSS explanation
                // max-w-3xl
                //   {max-width: 48rem/* 768 px */;}
                // xl:max-w-5xl
                //   @media (min-width: 1280px) {max-width: 64rem/* 1024px */; }
                // h-36
                //   {height: 9rem/* 144px */;}

                // These "sizes" result in almost the same behavior as 33vw.

                // A minimized Chrome window is 500px and will load the 128px
                // version. Later, when using 33vw, the 256px version will load.

                // That's because 33% (33vw) of 500px is 165px, so 256px loads.
                // (The resulting image is 148x144 when scaled with CSS.)

                // Note that this requires the following in next.config.js:
                /*
                module.exports = {
                images: {
                  imageSizes: [16, 32, 48, 64],
                  deviceSizes: [96, 128, 256, 384, 512, 640, 750, 828, 1080, 1200, 1920, 2048, 3840],
                },}
                */
                // You can inspect the image in the HTML code in Chrome in order
                // to find out its "intrinsic" size, as served by next.js.

                // Due to caching, you'll need to load a new private window at
                // the window size you want to test in Chrome.

                // You can also run Lighthouse in Google DevTools to test sizes.
              />
            </div>
          </div>
          <div>
            <div className="relative h-36">
              <Image
                src="/static/images/ocean.jpeg"
                className="object-cover rounded-full"
                layout="fill"
                sizes="33vw"
              />
            </div>
          </div>
          <div>
            <div className="relative h-36">
              <Image
                src="/static/images/ocean.jpeg"
                className="object-cover rounded-full"
                layout="fill"
                sizes="33vw"
              />
            </div>
          </div>
        </div>
      </div>

And here's my Next.js config file:

next.config.js

module.exports = withBundleAnalyzer({
  images: {
    /* This is because imageSizes is only used when generating the 1x/2x/3x srcSet for layout="fixed" or layout="intrinsic".

    The deviceSizes are used for layout="responsive" and layout="fill" which generates a srcSet with all the device sizes. */
    imageSizes: [16, 32, 48, 64], // This array is concatenated to deviceSizes.
    // imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], // Next.js default
    deviceSizes: [96, 128, 256, 384, 512, 640, 750, 828, 1080, 1200, 1920, 2048, 3840],
    // deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], // default
  },
  // pageExtensions: etc.

Hope this helps someone. And @styfle if you approve I'll open a pull request to make the changes to the docs. I don't want to do it right this second, because I could be entirely wrong here 😅

@styfle
Copy link
Member

styfle commented Mar 29, 2021

If you open a PR, we’ll take look 👍

I would also recommend a PR to MDN, since “sizes” is a web standard 🙂

@surjithctly
Copy link

surjithctly commented Apr 20, 2021

I think this is still not fixed. I have the same issue. I'm simply trying to achieve max-width:100% effect we used in normal CSS.

From next.js perspective, I want something in the middle of intrinsic and responsive

From the docs:

When intrinsic, the image will scale the dimensions down for smaller viewports but maintain the original dimensions for larger viewports.

When responsive, the image will scale the dimensions down for smaller viewports and scale up for larger viewports.

The problem is, while using intrinsic next/image does not provide multiple device sizes like responsive (640, 720 etc) instead it just gives 1x & 2x only.
When using responsive, it takes the whole container to fill in large screens. Not the max-width of image loaded.

So, how can I achieve something in-between?

Expected Result:

the image should scale the dimensions down for smaller viewports but maintain the original dimensions for larger viewports. but also generate srcSet defined from next.config deviceSizes (640, 720 etc)

If it's supported already, can someone guide me? If not, it's better to open this issue?

See Issue live on codesandbox

This should render at 200px maximum.

@AlexandraKlein
Copy link

AlexandraKlein commented Apr 20, 2021

When responsive, the image will scale the dimensions down for smaller viewports and scale up for larger viewports.

Would the following be an acceptable approach for your case?

 <div style={{ maxWidth: 200 }}>
    <Image width={200} height={200} layout="responsive" src="/pc.jpg" />
 </div>

@DoctorDerek
Copy link

DoctorDerek commented Apr 20, 2021 via email

@surjithctly
Copy link

surjithctly commented Apr 21, 2021

@AlexandraKlein @DoctorDerek we can make it work using a wrap div with fixed width.

But don’t you think it should be supported by default since it's already adding two wrapping divs? Why should we bloat the code again with another div?

@DoctorDerek
Copy link

DoctorDerek commented Apr 21, 2021 via email

@surjithctly
Copy link

I understand,

My question is can't they support it by default? I feel it's broken for this case.

maybe an additional props like PreserveMaxWidth = true so that the max-width automatically applies based on the image size.

@DoctorDerek
Copy link

DoctorDerek commented Apr 21, 2021 via email

@AlexandraKlein
Copy link

@DoctorDerek, I agree. One could add any CSS rules they like in their own custom Image component.

Ex:

import Image from "next/image";

const CustomImage = ({ preserveMaxWidth, width, height, ...props }) => (
  <div style={{ maxWidth: preserveMaxWidth ? width : "none" }}>
    <Image
      width={width}
      height={height}
      layout="responsive"
      src="/pc.jpg"
      {...props}
    />
  </div>
);

export default function IndexPage() {
  return (
    <CustomImage
      preserveMaxWidth
      width={200}
      height={200}
      layout="responsive"
      src="/pc.jpg"
    />
  );
}

codesandbox

@gregg-cbs
Copy link

gregg-cbs commented Jun 7, 2021

Im using "next": "^10.2.3"
This issue is so frustrating that we are going to have to create an image server just to handle sizing.
At least we can get lazy loading out of this image component.

But everything else needs to be reconsidered by the Next team. This component is almost impossible to figure out.

@gregg-cbs
Copy link

gregg-cbs commented Jun 7, 2021

Whats interesting is vw units cause resizing:

<Image 
  src={image} 
  alt={name + ' logo'}
  width={'33vw'}
  height={'33vw'}
  quality={100}
  layout="intrinsic"
/>

But 'px' doesnt:

<Image 
  src={image} 
  alt={name + ' logo'}
  width={'96px'}
  height={'96px'}
  quality={100}
  layout="intrinsic"
/>

And even then it doesnt make sense because an image size of 33vw is bigger on mobile than on desktop...

@DoctorDerek
Copy link

DoctorDerek commented Jun 7, 2021 via email

@gregg-cbs
Copy link

gregg-cbs commented Jun 29, 2021

@DoctorDerek -> thats why its weird that vw even has an impact and pixels dont.

Also your above recommendation does not seem to have any effect on my images.

<ImageWrapper style={{width: '76px', height: '76px', position: 'relative'}}>
	<Image 
	src={listing.imageUrl} 
	alt={listing.name} 
	quality={100}
	layout="fill"
	/>
</ImageWrapper>

The url that gets rendered out is:

...amazonaws.com%2Fd2866380-d410-11eb-b585-19e41e2e16b8.webp&w=1920&q=100"

@gregg-cbs
Copy link

gregg-cbs commented Jun 29, 2021

This works for me along with the devices sizes in the config.

<ImageWrapper>
  <Image 
	src={listing.imageUrl} 
	alt={listing.name} 
	width={'76px'}
	height={'76px'}
	quality={100}
	layout="intrinsic"
  />
</ImageWrapper>

The width specified on the Image needs to be in imageSizes in next.config.js otherwise it defaults to the closest size next has in their defaults which might not be close to the size you actually want.

So put your sizes in an array like this:

module.exports = {
    imageSizes:  [500, 400, 300, 200 ,100, 96, 76],
}

BUT it looks like if you do not have devicesSizes the behavior is inconsistent, i found this makes things stable:

module.exports = {
  images: {
    deviceSizes: [200],
    imageSizes:  [500, 400, 300, 200 ,100, 96, 86, 76, 64],
    domains: [process.env.AWS_S3_URL],
  },
};

Also it looks like depending on the DPI of the device is how big the image will render, so if you are using inspector in your browser and the image is bigger than expected, check the DPI and change it between 1, 2 and 3 to see the results.
image

I have now created custom devices so i can test across all DPIs.

Hope this helps. Documentation or implementation of this component definitely needs to be sorted out by the next team. Super unclear.

@DoctorDerek
Copy link

DoctorDerek commented Jun 29, 2021 via email

@gregg-cbs
Copy link

gregg-cbs commented Jun 30, 2021

@DoctorDerek
The imageWrapper is just my styled component which places the image where it needs to be in the layout. That is why its there.

I wouldn't mind having a look at your dynamic sizing, would be nice for this thread to have all bits and pieces consolidated here.

@DoctorDerek
Copy link

DoctorDerek commented Jun 30, 2021 via email

@neckaros
Copy link

neckaros commented Jul 3, 2021

These widths are used when the next/image component uses layout="fixed" or layout="intrinsic".

This is because imageSizes is only used when generating the 1x/2x/3x srcSet for layout="fixed" or layout="intrinsic".

The deviceSizes are used for layout="responsive" and layout="fill" which generates a srcSet with all the device sizes.

https://nextjs.org/docs/api-reference/next/image#sizes

Ohhh good to know. Isn’t deviceSizes a little counter intuitive name as it not only relate to device size but more the size matching the media query?

@DoctorDerek
Copy link

DoctorDerek commented Jul 3, 2021 via email

@neckaros
Copy link

neckaros commented Jul 3, 2021

True but they manage deprecation pretty well (exemple trailing slashes)

I’m not sure to understand why every layout but responsive and fill are the use the concatenation of the two arrays (looking at the code)?

@DoctorDerek
Copy link

DoctorDerek commented Jul 3, 2021 via email

@neckaros
Copy link

neckaros commented Jul 3, 2021

Really? I exclusively use layout=fill and thought both arrays were being combined. Could be wrong tho

In the merge talked about:

return { widths: configDeviceSizes, kind: 'w' }

in master it depends of the sizes attribute:

if (sizes && (layout === 'fill' || layout === 'responsive')) {

If you have any vw rule in sizes it takes everything in all arrays that is above the smallest deviceSizes * your smallest vw %
Could not understand this either. Maybe I’m reading it wrong?

@DoctorDerek
Copy link

DoctorDerek commented Jul 3, 2021

@neckaros Yeah seems like a bug to me, layout=fill could be used for full-width but is used for any object-cover use case.

Shouldn't it be

  if (
    typeof width !== 'number' ||
//    layout === 'fill' || // remove this line ?
    layout === 'responsive'
  ) {
    return { widths: configDeviceSizes, kind: 'w' }
  }

Seems like an easy fix 😀

Source:

if (
typeof width !== 'number' ||
layout === 'fill' ||
layout === 'responsive'
) {
return { widths: configDeviceSizes, kind: 'w' }
}

@leewalton2014
Copy link

I agree the image tags are not documented very well and it is abit fustrating to have to wrap the image in a div all the time to do resizing in the styles this video really helped me https://www.youtube.com/watch?v=7fqKzvjQj94

@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.