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

Add additional next/image layout modes #18637

Closed
2 tasks
Timer opened this issue Nov 1, 2020 · 38 comments
Closed
2 tasks

Add additional next/image layout modes #18637

Timer opened this issue Nov 1, 2020 · 38 comments
Assignees
Labels
Image (next/image) Related to Next.js Image Optimization.

Comments

@Timer
Copy link
Member

Timer commented Nov 1, 2020

Feature request

We should add further layout modes:

  • fixed-height (forces width: auto?)
  • flex-item
@Timer Timer added this to the iteration 12 milestone Nov 1, 2020
@Timer Timer self-assigned this Nov 1, 2020
@FDiskas
Copy link

FDiskas commented Nov 1, 2020

Also what about using image as a background? I would imagine some function what returns string to the image

@g-elwell
Copy link

g-elwell commented Nov 1, 2020

Also what about using image as a background? I would imagine some function what returns string to the image

The problem with returning a single image URL is you'd lost many of the optimisations that next/image provides i.e loading a suitable image size based on the current viewport.

In the past I've replicated CSS background-image with a real img element by using position: relative on the container and the following on an img inside of it:

position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
object-fit: cover;

This works really well and allows you to use srcset to automatically load the correct sized image for the viewport.

layout="fill" on next/image seems to be designed for this purpose, but doesn't have object-fit: cover so it distorts the image - maybe that would be a good addition to that mode?

@Timer
Copy link
Member Author

Timer commented Nov 1, 2020

@g-elwell you can easily pass that along:

<Image src="..." layout="fill" style={{ objectFit: 'cover' }} />

@FDiskas
Copy link

FDiskas commented Nov 1, 2020

@Timer you can easily pass that along:

<Image src="..." layout="fill" style={{ objectFit: 'cover' }} />

And result is:

<div><div><img layout="fill" data-src="/_next/image?url=https%3A%2F%2Fsource.unsplash.com%2F2560x1440%2Fweekly%3Fwater%2Cnature&amp;w=1200&amp;q=75" data-srcset="/_next/image?url=https%3A%2F%2Fsource.unsplash.com%2F2560x1440%2Fweekly%3Fwater%2Cnature&amp;w=320&amp;q=75 320w, /_next/image?url=https%3A%2F%2Fsource.unsplash.com%2F2560x1440%2Fweekly%3Fwater%2Cnature&amp;w=420&amp;q=75 420w, /_next/image?url=https%3A%2F%2Fsource.unsplash.com%2F2560x1440%2Fweekly%3Fwater%2Cnature&amp;w=768&amp;q=75 768w, /_next/image?url=https%3A%2F%2Fsource.unsplash.com%2F2560x1440%2Fweekly%3Fwater%2Cnature&amp;w=1024&amp;q=75 1024w, /_next/image?url=https%3A%2F%2Fsource.unsplash.com%2F2560x1440%2Fweekly%3Fwater%2Cnature&amp;w=1200&amp;q=75 1200w" class="" src="/_next/image?url=https%3A%2F%2Fsource.unsplash.com%2F2560x1440%2Fweekly%3Fwater%2Cnature&amp;w=1200&amp;q=75" srcset="/_next/image?url=https%3A%2F%2Fsource.unsplash.com%2F2560x1440%2Fweekly%3Fwater%2Cnature&amp;w=320&amp;q=75 320w, /_next/image?url=https%3A%2F%2Fsource.unsplash.com%2F2560x1440%2Fweekly%3Fwater%2Cnature&amp;w=420&amp;q=75 420w, /_next/image?url=https%3A%2F%2Fsource.unsplash.com%2F2560x1440%2Fweekly%3Fwater%2Cnature&amp;w=768&amp;q=75 768w, /_next/image?url=https%3A%2F%2Fsource.unsplash.com%2F2560x1440%2Fweekly%3Fwater%2Cnature&amp;w=1024&amp;q=75 1024w, /_next/image?url=https%3A%2F%2Fsource.unsplash.com%2F2560x1440%2Fweekly%3Fwater%2Cnature&amp;w=1200&amp;q=75 1200w" style="visibility: visible;"></div></div>

No css is applied and some extra couple divs are added.

@Timer
Copy link
Member Author

Timer commented Nov 1, 2020

@FDiskas you have to be on next@canary.

@g-elwell
Copy link

g-elwell commented Nov 2, 2020

@g-elwell you can easily pass that along:

<Image src="..." layout="fill" style={{ objectFit: 'cover' }} />

Sorry, what I meant to say was object-fit: cover may be a good default setting on the img when you're using layout="fill"

I appreciate you can pass it in, and either way I will be using that mode for background images all the time!

I just figure I'd want cover 99% of the time and override with contain for certain use cases. Don't think I'd ever leave it as the current default.

@heymartinadams
Copy link

Using layout: fill and style: { objectFit: 'cover' } I’m somehow still getting a squished image.

<Image
  {...{
    layout: 'fill', // Also tried `fixed`, `intrinsic`, `responsive`
    src: '...',
    style: { objectFit: 'cover' } // also tried `contain`
    // height: bgheight,
    // width: bgwidth
  }}
/>

@FDiskas
Copy link

FDiskas commented Nov 2, 2020

@heymartinadams

      <div className={styles.container}>
        <Image
          className={styles.background}
          src="https://source.unsplash.com/2560x1440/weekly?nature"
          layout="fill"
        />
      </div>
.container {
  position: fixed;
  height: 100vh;
  width: 100vw;
  overflow: hidden;
  z-index: -1;
}
.background {
  object-fit: cover;
}

image

@leerob
Copy link
Member

leerob commented Nov 6, 2020

@Timer Thoughts on adding the above background image workaround to the docs? There was a request on Discord for this.

@styfle
Copy link
Member

styfle commented Nov 6, 2020

@leerob Its in the docs on canary and updated in the examples on canary https://github.com/vercel/next.js/blob/canary/examples/image-component/pages/background.js

Also see the usage for layout=fill here: https://github.com/vercel/next.js/blob/canary/examples/image-component/pages/layout-fill.js

@lxsmnsyc
Copy link

lxsmnsyc commented Nov 7, 2020

Is there a way for the images to have it's height based on the parent while maintaining aspect ratio? For example, the layout below:

.container {
  width: auto;
  height: 100%;
}
<div className="container>
   {/* assume all forms of layout */}
  <Image src="/my/image.png" />
</div>

Doesn't work and does not maintain the aspect ratio of the image. (It has the height of the parent but 0 width).

It broke some of the images with this kind of styling, therefore I reverted these into the native image element.

@LosYear
Copy link

LosYear commented Nov 7, 2020

Is there any way to use next/image for fixed-height but dynamic width right now?

@dawnerd
Copy link

dawnerd commented Nov 9, 2020

Yeah this latest change broke my images as well and layout="fill" doesn't work. Was using unsized before. Can we get an option that acts like unsized did? I really don't want inline styles being applied as I'm handling the responsive styles myself.

@Timer Timer modified the milestones: 10.x.x, iteration 13 Nov 9, 2020
@deathemperor
Copy link

Yeah this latest change broke my images as well and layout="fill" doesn't work. Was using unsized before. Can we get an option that acts like unsized did? I really don't want inline styles being applied as I'm handling the responsive styles myself.

same, unsized worked really well. Changing to layout="fill" making all Images with that attribute stacks up because each has display: block; overflow: hidden; position: absolute; top: 0px; left: 0px; bottom: 0px; right: 0px; box-sizing: border-box; margin: 0px; css

@mohux
Copy link

mohux commented Nov 10, 2020

same, layout fill seems to break the image

@mohux
Copy link

mohux commented Nov 10, 2020

same, layout fill seems to break the image

Well it worked when I gave the stylings to it's parent div since fill is taking 100% width and 100% height

@Timer Timer added point: 5 and removed point: 3 labels Nov 13, 2020
@timneutkens timneutkens added this to the iteration 16 milestone Jan 15, 2021
@colepeters
Copy link
Contributor

Hi folks, I'm following up on an issue raised in #18637, #18911, and later by myself in #21914 (oops). @Timer mentioned in #18637 that this would the right place to follow up on this topic.

In #18637, @Timer said the issue in question (extra whitespace being added below an image) is an expected behaviour, but that doesn't seem quite right to me. My understanding is that next/image is a drop-in replacement for the img element — this would seem to break that contract. I realise that a component like next/image isn't a straightforward thing, so I can understand that there might be some complexity around this issue, but the solutions that have been surfaced so far (adding wrappers with font-size: 0, for example) don’t exactly sit well. I haven’t seen this issue discussed here, so I’m wondering if anyone in the know can comment on whether there are plans to address this?

Thanks very much, and thanks to everyone for all your work on this component!

@eddyw
Copy link

eddyw commented Feb 12, 2021

Hi folks, I'm following up on an issue raised in #18637, #18911, and later by myself in #21914 (oops). @Timer mentioned in #18637 that this would the right place to follow up on this topic.

In #18637, @Timer said the issue in question (extra whitespace being added below an image) is an expected behaviour, but that doesn't seem quite right to me. My understanding is that next/image is a drop-in replacement for the img element — this would seem to break that contract. I realise that a component like next/image isn't a straightforward thing, so I can understand that there might be some complexity around this issue, but the solutions that have been surfaced so far (adding wrappers with font-size: 0, for example) don’t exactly sit well. I haven’t seen this issue discussed here, so I’m wondering if anyone in the know can comment on whether there are plans to address this?

Thanks very much, and thanks to everyone for all your work on this component!

It isn't a drop-in replacement for img. Because it uses div wrappers, that's enough to break semantic HTML5 validation. For instance, we replaced our Image component with the one provided by Next.js in a project, this broke all blog posts because you can't have Next.js Image in a paragraph because a div automatically closes a p tag and it's not valid HTML5.

I mentioned some of this issues in this same thread (reply just above yours)

We ended up reverting those changes. We still use Next.js Image default loader but without their Image component, just to generate srcset.

@andrei-zgirvaci
Copy link

andrei-zgirvaci commented Feb 22, 2021

I managed to fix this for myself, by adding a wrapper with the specific width and height, adding the same width and height for the image, and setting the layout to "fixed". You probably can achieve the same effect with the layout: "fill", but in my case "fill" messes up my other elements.

<div
  style={{ width: '326px', height: '445px' }}
>
  <Image
    src="/images/Profile.png"
    layout="fixed"
    width={326}
    height={445}
  />
</div>

This is a specific case where I know the exact image width and height, which of course doesn't fix the main issue here, but hope this helps other people who have the same case as me. 🙏

@Timer Timer modified the milestones: iteration 17, 10.x.x Mar 15, 2021
@AlexandraKlein
Copy link

AlexandraKlein commented Mar 19, 2021

Targeting the parent div of the component (the one with display: inline-block) and adding vertical-align: top; solves it, though not completely sure what other implications this may have.

@jonrrivera
Copy link

jonrrivera commented Apr 30, 2021

Adding <Image layout="responsive width='100%' height='100%' /> to the component, and defining width and height elements to the parent proves to work similar to native img behavior.

JSX:
<div className={styles.prodImg}> <Image layout="responsive" className={styles.imgs} src={variantImage.src} alt={this.props.product.title} quality="85" width='100%' height='100%' priority={true} /> </div>

SCSS:
.prodImg { display: inline-block; width: 100%; height: 100%; }

@bodrovphone
Copy link

Adding <Image layout="responsive width='100%' height='100%' /> to the component, and defining width and height elements to the parent proves to work similar to native img behavior.

JSX:
<div className={styles.prodImg}> <Image layout="responsive" className={styles.imgs} src={variantImage.src} alt={this.props.product.title} quality="85" width='100%' height='100%' priority={true} /> </div>

SCSS:
.prodImg { display: inline-block; width: 100%; height: 100%; }

Worked for me. Thanks @jonrrivera

@fdmmarshall
Copy link

Is there a solution to remove the display: 'inline-block' from the outer <div> that wraps the image? I have no been successful at over writing it. Thanks!

@Timer Timer removed their assignment Sep 20, 2021
@styfle styfle modified the milestones: 11.x.x, 12.0.4 Nov 5, 2021
@timneutkens timneutkens removed this from the 12.0.5 milestone Nov 17, 2021
@timneutkens timneutkens added the Image (next/image) Related to Next.js Image Optimization. label Nov 17, 2021
@kara kara assigned atcastle and unassigned kara Jan 31, 2022
styfle pushed a commit that referenced this issue Mar 14, 2022
This PR adds a new layout mode for images called `raw`, as discussed with the core team a while back. This mode has the following characteristics:
 - No wrapper `span` around the `img` element
 - No sizer svg
 - Almost no styles automatically added to the `img` element
 - `style` parameter is allowed and is passed through to the underlying `img` element

This also adds documentation changes to describe the new component.

There are a few tradeoffs and DX decisions that may warrant discussion/revision before merging. I'll add a few comments to highlight those issues.

- Related to #18637
@atcastle
Copy link
Collaborator

We've added a new experimental "raw" layout mode which I believe addresses a lot of the issues people have had with the existing image layout modes. I've opened #35493 to gather feedback on the new mode before we bring it out of experimental. I'd appreciate if anyone subscribed to this thread could take a look at the new mode and tell me what you think.

@styfle
Copy link
Member

styfle commented Sep 22, 2022

We shipped next/future/image and removed the layout prop in Next.js 12.3

Learn more: https://nextjs.org/blog/next-12-3


Update: Next.js 13 renamed next/future/image to next/image so there is no more “layout” prop.

Learn more: https://nextjs.org/blog/next-13

@styfle styfle closed this as completed Sep 22, 2022
@github-actions
Copy link
Contributor

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Image (next/image) Related to Next.js Image Optimization.
Projects
None yet
Development

No branches or pull requests