preamble
- Hey, it's Immerse.
- Article first published on personal blog [], more on individual blogs
- Reprint Note: For reprints, please include the original source and copyright notice in the header of the article!
a factor (leading an effect)
- Recently went livepersonal blogThe fragment page has a large number of images, the experience of loading images is very poor, can be said to be a cliff, from 0-1 there is no transition at all (this affects the layout of the page and the user experience, for the images that have set the image width and height of the image is fine, if not, there will be a process of the image to support the height of the process)
coincide
- In preparation for writing this article on the same day the front-end South Nine big brother published an article, I straight call big data bull 👍🏻Article: Click to view
- We'll discuss a few other options in this post, so without further ado, let's get back to the point.
- For regular image optimization will not be repeated here, roughly as follows:
- Compressing images, using CSS sprites, lazy loading, preloading, CDN caching, proper image formats, Seven Bulls CDN image parameters, and more!
- For regular image optimization will not be repeated here, roughly as follows:
explorations
- Here are a few of the scenarios mentioned in this post (some of the sample code is React since the personal project is based on Next)
- (1) Use the main color of the picture
- (2) Using a certain color
- (3) Using thumbnails of images
- (4) Use Blur + Compression
- (5) Image Placeholders
Option 1: Use the main color of the picture
- In our day-to-day development, our image
src
It may be dynamic, i.e. a stringstring
url, when we specifyplaceholder="blur"
When you add theblurDataURL Attributes.
import Image from 'next/image';
// Pixel GIF code adapted from /a/33919020/266535
const keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const triplet = (e1: number, e2: number, e3: number) =>
(e1 >> 2) +
(((e1 & 3) << 4) | (e2 >> 4)) +
(((e2 & 15) << 2) | (e3 >> 6)) +
(e3 & 63);
const rgbDataURL = (r: number, g: number, b: number) =>
`data:image/gif;base64,R0lGODlhAQABAPAA${
triplet(0, r, g) + triplet(b, 255, 255)
}/yH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==`;
const Color = () => (
<div>
<h1>Image Component With Color Data URL</h1>
<Image
alt="Dog"
src="/"
placeholder="blur"
blurDataURL={rgbDataURL(237, 181, 6)}
width={750}
height={1000}
style={{
maxWidth: '100%',
height: 'auto'
}}
/>
<Image
alt="Cat"
src="/"
placeholder="blur"
blurDataURL={rgbDataURL(2, 129, 210)}
width={750}
height={1000}
style={{
maxWidth: '100%',
height: 'auto'
}}
/>
</div>
);
export default Color;
Option 2: Use a certain color
- exist
Medium Configurationplaceholder because of
color
and then use thebackgroundColor
causality
//
= {
images: {
placeholder: 'color',
backgroundColor: '#121212'
}
};
// utilization
<Image src="/path/to/" alt="image title" width={500} height={500} placeholder="color" />
Option 3: Use thumbnails of images
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Progressive image loading</title>
<style>
.placeholder {
background-color: #f6f6f6;
background-size: cover;
background-repeat: no-repeat;
position: relative;
overflow: hidden;
}
.placeholder img {
position: absolute;
opacity: 0;
top: 0;
left: 0;
width: 100%;
transition: opacity 1s linear;
}
.placeholder {
opacity: 1;
}
.img-small {
filter: blur(50px);
transform: scale(1);
}
</style>
</head>
<body>
<div
class="placeholder"
data-large="/work/143/24/42b204ae3ade4f38/1_sg"
>
<img
src="/work/143/24/5307e9778a944f93/1_sg"
class="img-small"
/>
<div style="padding-bottom: 66.6%"></div>
</div>
</body>
</html>
<script>
= function () {
var placeholder = ('.placeholder'),
small = ('.img-small');
// 1. Show small image and load
var img = new Image();
= ;
= function () {
('loaded');
};
// 2. Load large image
var imgLarge = new Image();
= ;
= function () {
('loaded');
};
(imgLarge);
};
</script>
Option 4: Use blurring + compression of images
//
'use client';
import React, { useState, useEffect } from 'react';
import imageCompression from 'browser-image-compression';
interface ProgressiveImageProps {
src: string;
alt?: string;
width?: number;
height?: number;
layout?: 'fixed' | 'responsive' | 'fill' | 'intrinsic';
className?: string;
style?: ;
}
export const ProgressiveImage: <ProgressiveImageProps> = ({
src,
alt = '',
width,
height,
layout = 'responsive',
className = '',
style = {}
}) => {
const [currentSrc, setCurrentSrc] = useState<string>(src);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [blurLevel, setBlurLevel] = useState<number>(20);
useEffect(() => {
let isMounted = true;
const loadImage = async () => {
try {
// Load and compress the original image
const response = await fetch(src);
const blob = await ();
// Generate low quality preview images
const tinyOptions = {
maxSizeMB: 0.0002,
maxWidthOrHeight: 16,
useWebWorker: true,
initialQuality: 0.1
};
const tinyBlob = await imageCompression(blob, tinyOptions);
if (isMounted) {
const tinyUrl = (tinyBlob);
setCurrentSrc(tinyUrl);
// Starting to gradually reduce the blurriness
startSmoothTransition();
}
// Load original image
const highQualityImage = new Image();
= src;
= () => {
if (isMounted) {
setCurrentSrc(src);
// When the high quality image has finished loading,Continued smooth transition
setTimeout(() => {
setIsLoading(false);
}, 100);
}
};
} catch (error) {
('Error loading image:', error);
if (isMounted) {
setCurrentSrc(src);
setIsLoading(false);
}
}
};
const startSmoothTransition = () => {
// through (a gap)20pxThe blurring of the gradual transition to10px
const startBlur = 20;
const endBlur = 10;
const duration = 1000; // 1unit of angle or arc equivalent one sixtieth of a degree
const steps = 20;
const stepDuration = duration / steps;
const blurStep = (startBlur - endBlur) / steps;
let currentStep = 0;
const interval = setInterval(() => {
if (currentStep < steps && isMounted) {
setBlurLevel(startBlur - blurStep * currentStep);
currentStep++;
} else {
clearInterval(interval);
}
}, stepDuration);
};
setIsLoading(true);
setBlurLevel(20);
loadImage();
return () => {
isMounted = false;
if (currentSrc && ('blob:')) {
(currentSrc);
}
};
}, [src]);
const getContainerStyle = (): => {
const baseStyle: = {
position: 'relative',
overflow: 'hidden'
};
switch (layout) {
case 'responsive':
return {
...baseStyle,
maxWidth: width || '100%',
width: '100%'
};
case 'fixed':
return {
...baseStyle,
width: width,
height: height
};
case 'fill':
return {
...baseStyle,
width: '100%',
height: '100%',
position: 'absolute',
top: 0,
left: 0
};
case 'intrinsic':
return {
...baseStyle,
maxWidth: width,
width: '100%'
};
default:
return baseStyle;
}
};
const getImageStyle = (): => {
const baseStyle: = {
filter: isLoading ? `blur(${blurLevel}px)` : 'none',
transition: 'filter 0.8s ease-in-out', // Increased transition time
transform: 'scale(1.1)', // Zoom in slightly to prevent edges from appearing when blurred
...style
};
switch (layout) {
case 'responsive':
return {
...baseStyle,
width: '100%',
height: 'auto',
display: 'block'
};
case 'fixed':
return {
...baseStyle,
width: width,
height: height
};
case 'fill':
return {
...baseStyle,
width: '100%',
height: '100%',
objectFit: 'cover'
};
case 'intrinsic':
return {
...baseStyle,
width: '100%',
height: 'auto'
};
default:
return baseStyle;
}
};
return (
<div className={`${className}`} style={getContainerStyle()}>
{currentSrc && <img src={currentSrc} alt={alt} style={getImageStyle()} />}
</div>
);
};
// utilization
<ProgressiveImage
src={photo}
alt={}
width={300}
height={250}
layout="responsive"
className="h-full min-h-[150px]"
/>
Option 5: Picture Placeholders
- (used form a nominal expression)next/image subassembliesplaceholder property provides an option
blur
The default isempty
-
blur
A blurry preview image will be generated (but this option increases the initial loading practice as it takes time to generate the blurry image) - Note: If the
placeholder="blur"
You must use theimport
The way images are statically introduced so that they can be pre-processed for progressive loading
-
import Image from 'next/image';
import mountains from '/public/';
const PlaceholderBlur = () => (
<div>
<h1>Image Component With Placeholder Blur</h1>
<Image
alt="Mountains"
src={mountains}
placeholder="blur"
width={700}
height={475}
style={{
maxWidth: '100%',
height: 'auto'
}}
/>
</div>
);
export default PlaceholderBlur;
summarize
- The first impression of a product is important and a good user experience is necessary for the product.
- Thanks for reading and we'll see you next time!