24
loading...
This website collects cookies to deliver better user experience
Check the full code here
We can use the built-in placeholder image in Next.js,
but we might need something that resembles the actual image for some cases, like cover images.
Check this blog for more info
import {getPlaiceholder} from 'plaiceholder'
const placeholder = await getPlaiceholder(uri, { size: 64 })
// OR
const placeholder = await getPlaiceholder(uri)
// `size` decides how many blocks there will be
// ranges from 4 to 64
// default is 4
getPlaiceholder
returns a promise
of object with the following properties:base64
blurhash
css
img
svg
img
and svg
property.plaiceholder
's version. svg
element.function BlurringImage({ svg }){
const Svg = svg[0]
const svgProps = svg[1]
return <Svg {...svgProps}>
{/* TODO */}
</Svg>
}
rect
's, which will render as svg
children.function BlurringImage({ svg }){
// ...
const rectangles = svg[2]
return <Svg {...}>
{rectangles.map((rect) => {
const Rect = rect[0]
const rectProps = rect[1]
<Rect {...rectProps} key={`${rectProps.x}${rectProps.y}`} />
)}}
</Svg>
}
function BlurringImage({ svg }){
// ...
const svgProps = svg[1]
return <Svg
style={{
...svgProps.style,
filter: `blur(5px)`,
}}
>
{...}
</Svg>
}
NOTE: Make sure to apply an appropriate filter value
For svg metadata
with fewer rect
s, the result might looks like this:
svg
and Image
can be optionally wrapped in a another component(for styling).img
props in the next Image
component.import Image from 'next/image'
function BlurringImage({ img }){
// ...
return <Container>
<Svg {...}>
<Image {...img} />
</Container>
// Create the Container in any way you want
}
useState
and the Image
's' onLoadingComplete
callback method.function BlurringImage({...}){
// ...
const [hasPlaceholder, setHasPlaceholder] = useState(true)
return <Container>
{hasPlaceholder && <Svg {...} />}
<Image {...} onLoadingComplete={() => setHasPlaceholder(false)} />
</Container>
}
import React, {useState} from 'react'
import styled from '@emotion/styled'
import Image from 'next/image'
export function BlurringImage({
svg: [Svg, svgProps, rectangles],
img,
alt,
style,
blurLevel = 5,
height = undefined,
width = undefined,
...props
}) {
const [hasPlaceholder, setHasPlaceholder] = useState(true)
return (
<Container style={style}>
{hasPlaceholder && (
<Svg
{...svgProps}
style={{
...svgProps.style,
filter: `blur(${blurLevel}px)`,
}}
>
{rectangles.map(([Rect, rectProps]) => (
<Rect {...rectProps} key={`${rectProps.x}${rectProps.y}`} />
))}
</Svg>
)}
<Image
{...img}
{...props}
height={height}
width={width}
alt={alt}
onLoadingComplete={() => setHasPlaceholder(false)}
/>
</Container>
)
}
const Container = styled.div`
position: relative;
overflow: hidden;
height: 100%;
width: 100%;
`;
import {getPlaiceholder} from 'plaiceholder';
import {BlurringImage} from '../components/BlurringImage';
export default function IndexPage({img, svg}) {
return (
{/* <SomeHeaderComponent /> */}
<BlurringImage
img={img}
svg={svg}
layout="responsive"
width={1200}
height={800}
/>
)
}
// or getServerSideProps depending on your needs
export async function getStaticProps() {
const uri = 'https://i.imgur.com/gf3TZMr.jpeg';
const {img, svg} = await getPlaiceholder(uri, {
size: 64,
});
return {
props: {
img,
svg,
},
}
}