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

Support picture tag in next/image #25683

Closed
wants to merge 9 commits into from

Conversation

ascorbic
Copy link
Contributor

@ascorbic ascorbic commented Jun 1, 2021

Feature

  • Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
  • Related issues linked using fixes #number
  • Integration tests added
  • Documentation added
  • Telemetry added. In case of a feature if it's used or not.

Feature request: #25393

Currently next/image only supports next-gen images such as WebP via Accept header, because there's no way to handle fallback for old browsers. This means that image hosts or CDNs that only support changing format based on the URL cannot safely deliver next-gen formats. It also makes it harder to cache images.

The standards-compliant way to do this is to generate a <picture> tag with a <source> tag for each supported format.

This PR keeps the default behavior the same: it generates an <img> tag and uses content negotiation in the server for next-gen formats. However it adds a "formats" key to the image config, which can include next gen image formats. The supproted values for this depends on the handler, and would be just webp by default. If the formats array is present, then the <img> tag would be exactly the same as with auto format, but it would be wrapped with a <picture> tag and would include a <source> element for each requested type, with type attribute containing the mimetype. These pass an extra "format" option to the handler function when generating the URLs. The default handler would generate these URLs with an additional f parameter, which the image server would use to choose a format to generate.

The server implementation adds an optional f param, which if set to a valid next-gen image format (i.e. WebP), then returns that format, ignoring accept headers.

This is fully backwards-compatible, as the <img> tag is unchanged and still uses the auto format, and the <picture> tag would only be included if the formats array was included in the config.

I have included an implementation of the component and the server, integration tests for both, and docs. I have not included telemetry (because I'm unsure of the best way to add it).

@ijjk ijjk added the type: next label Jun 1, 2021
@ascorbic ascorbic marked this pull request as ready for review June 2, 2021 09:37
@zomars
Copy link

zomars commented Sep 29, 2021

Would this work for using a totally different image ant certain size for art direction?

@shawninder
Copy link

I was hoping to use the <picture> tag along with my next/image <Image> tags to fetch a different image based on the user's preferred color scheme.

Would this kind of use-case be supported if/when this PR goes through?

Here's what I have in mind specifically. The following code works with <img> but fails with <Image> (probably because of the <span> being added in there by next/image):

<picture>
  <source
    srcSet="https://via.placeholder.com/100/333333/ffffff.png"
    media="(prefers-color-scheme: dark)"
  />
  <img
    src='https://via.placeholder.com/100/dddddd/000000.png'
    width='100px'
    height='100px'
    alt='Placeholder image'
  />
</picture>

@tx0c
Copy link

tx0c commented May 14, 2022

+1 🆙 what's the progress since the PR opened for almost a full year? @ascorbic

@leerob
Copy link
Member

leerob commented May 14, 2022

We're exploring options for where to take next/image based on community feedback and will have something to share in the next few months.

@ijjk ijjk force-pushed the canary branch 3 times, most recently from df8579c to 47e5ebe Compare October 25, 2022 16:15
@trickydisco78
Copy link

Any updates on this @leerob ? Looks like it's not in next 13 unless i've missed it?

@ijjk ijjk force-pushed the canary branch 2 times, most recently from e078ebe to 6b863fe Compare December 2, 2022 05:49
@NiedziolkaMichal
Copy link
Contributor

@ascorbic This will screw up pseudo-classes like :first-child, :nth-of-type used on the image.

@ijjk ijjk requested a review from feedthejim as a code owner May 4, 2023 16:19
@leerob
Copy link
Member

leerob commented Jun 29, 2023

Update: We have extracted the core logic from next/image into a new unstable_getImgProps() function.

This allows usage outside of <Image>, such as:

  1. Working with background-image or image-set
  2. Working with canvas context.drawImage() or simply new Image()
  3. Working with <picture> media queries to implement Art Direction or Light/Dark Mode images

Example

import { unstable_getImgProps as getImgProps } from 'next/image'

export default function Page() {
  const common = { alt: 'Hero', width: 800, height: 400 }
  const { props: { srcSet: dark } } = getImgProps({ ...common, src: '/dark.png' })
  const { props: { srcSet: light, ...rest } } = getImgProps({ ...common, src: '/light.png' })

  return (<picture>
  <source media="(prefers-color-scheme: dark)" srcSet={dark} />
  <source media="(prefers-color-scheme: light)" srcSet={light} />
  <img {...rest} />
</picture>)
}

PR: #51205

@leerob leerob closed this Jun 29, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 29, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants