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 placeholder="blur" to Image component #18858

Closed
styfle opened this issue Nov 5, 2020 · 36 comments
Closed

Add placeholder="blur" to Image component #18858

styfle opened this issue Nov 5, 2020 · 36 comments
Assignees
Milestone

Comments

@styfle
Copy link
Member

styfle commented Nov 5, 2020

Today, Next.js shows an empty placeholder when using loading="lazy" (the default behavior).

We would like to add a placeholder="blur" option that shows a low res, blurred image until the actual image has been loaded.

The blurred placeholder must work with any loader value and ideally the image would be inlined as a Data URL instead of incurring an additional HTTP request.

We should also consider other placeholder options such as placeholder="skeleton" or a user-defined class.

Prior Art

@styfle styfle added this to the iteration 12 milestone Nov 5, 2020
@larbisahli
Copy link

larbisahli commented Nov 6, 2020

This will do: https://github.com/joe-bell/next-placeholder
They are using blurhash and Base64.

@Timer Timer modified the milestones: iteration 12, 10.x.x Nov 6, 2020
@joe-bell
Copy link
Contributor

joe-bell commented Nov 6, 2020

Hey friends, thanks for the mention of next-placeholder

Just a heads up that I'm working on a new strategy which, from early testing, has shown to be faster than any existing "blur" placeholder option out there. It's pretty much done but I need to do some more testing and documentation before I release

More than happy to collaborate with the Next.js core team to discuss further if this is urgent

@dohomi
Copy link

dohomi commented Nov 20, 2020

I think for now the easiest solution would be if the next/image component would enable a placeholder prop which is a react component. This would be a good solution because in some cases the blurred placeholder might not be wanted.

<Image
  placeholder={() => <div style={{backgroundColor: 'grey'}} />}

@joe-bell
Copy link
Contributor

I've just launched Plaiceholder; the lastest iteration of next-placeholder.

You can use the "studio" UI or the open-source functions to create pure CSS blurred image placeholders ✨

@jakewies
Copy link

This would be a really neat feature.

I have been trying to implement some form of loading skeleton for an e-commerce project and I'm struggling to do it right with next/image. What's tripping me up is the conditional: if !image show skeleton, else show image. It looks like the image will always be there (because SSG), so I never actually see the skeleton. However, I still get this very short period of empty space where the image should be during page load. Would love to tap into that for better UX.

@kumarldh
Copy link

I moved to next/image, could see improvements in LCP. However, I do not have placeholder images now...

@dandv
Copy link

dandv commented Jan 10, 2021

Great to see this being worked on. The lack of progressive image loading is the first thing Next.js is inferior to Gatsby at, in their comparison.

@coopbri
Copy link
Contributor

coopbri commented Jan 10, 2021

@dandv I agree completely. As a Gatsby convert, native progressive image loading is the one feature I miss from it. In the meantime, I am using @cyrilwanner's next-optimized-images with the lqip (placeholder) and webp (final render) loaders and am happy to share the code if anyone is looking for a solution right now.

@mnikolaus
Copy link

@coopbri are you using both next/image with next-optimized-images fallback? If so, feel free to share some resources with the community. Thx! 🙂

@joe-bell
Copy link
Contributor

If anyone's stuck creating an image placeholder in the meantime, there's a Next.js example over in the plaiceholder repo:

Hope this helps!

@coopbri
Copy link
Contributor

coopbri commented Jan 12, 2021

@mnikolaus I am using both packages, but not in the way you probably expect (working together). Basically, I have one Image component, with a boolean prop called blur. If blur is passed into the component (i.e. true), then it renders the blur up (lqip → webp) image. If blur is not passed into the component/false then it uses the next/image component.

The ideal situation I was looking for was an image loaded with next/image since it has nice optimizations (like easy lazy loading support), so my plan was to stop using next-optimized-images as soon as a blur placeholder feature like in this thread is merged into Next. With that being said, I would gladly dig deeper and try to merge blur up support into next/image.

@mnikolaus
Copy link

@coopbri I would expect it that way to work 🙂 Can you just share your next config of how you achieved that? Thanks!

@coopbri
Copy link
Contributor

coopbri commented Jan 15, 2021

@mnikolaus Absolutely! I am actually just using similar code to the next-optimized-images installation docs, no other config needed. If you would like to see any more code please do let me know.

kodiakhq bot pushed a commit that referenced this issue Apr 30, 2021
This is the image component implementation of the blurry placeholder as described in #24004. The matching server side implementation is currently planned.

## Feature

- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issue #18858 
- [x] Integration tests added

(Documentation and telemetry to follow after server side is implemented)
@timneutkens timneutkens modified the milestones: Iteration 19, Iteration 20 May 3, 2021
flybayer pushed a commit to blitz-js/next.js that referenced this issue Jun 1, 2021
This is the image component implementation of the blurry placeholder as described in vercel#24004. The matching server side implementation is currently planned.

## Feature

- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issue vercel#18858 
- [x] Integration tests added

(Documentation and telemetry to follow after server side is implemented)
@itxtoledo
Copy link

https://github.com/vercel/next.js/releases/tag/v10.2.4-canary.12

@Daiz
Copy link

Daiz commented Jun 14, 2021

I noticed that the implementation in #25945 doesn't add any kind of scaling to hide the white edges that come about as a result of the blurring - plaiceholder suggest a transform: scale(1.5) by default which does a nice job of dealing with that, and I think would good for placeholder=blur to either do the same by default or at least have an easy way to do it yourself (which I think would be complicated in the current implementation).

@styfle
Copy link
Member Author

styfle commented Jun 15, 2021

This feature is available in Next.js 11! 🎉

Learn more:

If you run into any bugs, please create a new issue with the steps to reproduce and we'll take a look, thanks!

@styfle styfle closed this as completed Jun 15, 2021
@vicasas
Copy link

vicasas commented Jun 15, 2021

@styfle Cool! more and more new things are being achieved that further enrich Next.js. But I have a doubt to admit a skeleton or a custom component load is there an issue for this?

@styfle
Copy link
Member Author

styfle commented Jun 15, 2021

You can use the blurDataURL prop to make your own placeholder.

@dohomi
Copy link

dohomi commented Jun 16, 2021

The example shows a picture of the filesystem. Will there be an example of remote images with the blur effect? That would be helpful to see how that would be implemented

@joe-bell
Copy link
Contributor

joe-bell commented Jun 16, 2021

For remote images, you could use plaiceholder to get the img attributes and base64 placeholder.

Demo
https://with-next.plaiceholder.co/base64/single

Code

import * as React from "react";
import { InferGetStaticPropsType } from "next";
import Image from "next/image";
import { getPlaiceholder } from "plaiceholder";

export const getStaticProps = async () => {
  const { base64, img } = await getPlaiceholder(
    "https://images.unsplash.com/photo-1621961458348-f013d219b50c?auto=format&fit=crop&w=2850&q=80",
    { size: 10 }
  );
  return {
    props: {
      imageProps: {
        ...img,
        blurDataURL: base64,
      },
    },
  };
};

const ExamplePage: React.FC<InferGetStaticPropsType<typeof getStaticProps>> = ({
  imageProps,
}) => <Image {...imageProps} placeholder="blur" />;

export default ExamplePage;

cc @dohomi


See also #26168 (comment)

kodiakhq bot pushed a commit that referenced this issue Jun 16, 2021
It was mentioned in Issue #18858 that we might add a `placeholder="skeleton"` but that didn't ship with Next.js 11 because it would likely need to handle additional config such as light mode / dark mode, speed, duration, etc.

So this PR adds an example of `blurDataURL` usage with a nice shimmer animation (sometimes called a skeleton).
@kamami
Copy link

kamami commented Jun 18, 2021

The blurred image does not take the styles (border-radius) of the component into account.

flybayer pushed a commit to blitz-js/next.js that referenced this issue Jun 24, 2021
It was mentioned in Issue vercel#18858 that we might add a `placeholder="skeleton"` but that didn't ship with Next.js 11 because it would likely need to handle additional config such as light mode / dark mode, speed, duration, etc.

So this PR adds an example of `blurDataURL` usage with a nice shimmer animation (sometimes called a skeleton).
@duveborg
Copy link

this is not usable with https://github.com/woltapp/blurhash , right?

@controversial
Copy link
Contributor

@duveborg that's correct

@thomcrielaardBCU
Copy link

Is there any way to apply styling to the blur image (P.E. resizemode)?

@ivansevillaa
Copy link

Hi, @duveborg is possible if you use https://github.com/ivansevillaa/use-next-blurhash. You just need to pass the hash generated to the hook, and it will return the blurred image to pass to the Image Component.

@WillSquire
Copy link

I think for now the easiest solution would be if the next/image component would enable a placeholder prop which is a react component. This would be a good solution because in some cases the blurred placeholder might not be wanted.

<Image
  placeholder={() => <div style={{backgroundColor: 'grey'}} />}

Is this not a good idea? It seemed like the obvious solution, so I just assumed it was the API. Was shocked to find it wanted a string of empty or blur?

@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.
Projects
None yet
Development

No branches or pull requests