图片加载体验 🚀
渐进式图片是一种优化网页图片加载体验的技术。当页面中的图片较大时,
传统的加载方式会让用户看到一片空白(白屏😣),直到图片完全加载完成才能显示。而渐进式图片则先显示一个
模糊的缩略图👀,随着图片数据的逐步加载,图片会变得越来越清晰✨。
渐进式图片,我们可能或多或少见过的——页面上有个模糊的图片,然后逐渐变得清晰。这种效果是不是很神奇呢?🤔
这种做法就是,当页面上有一些图片资源比较大的时候,传统方式需要用户盯着白屏⏳等待很久,体验感非常不好😞。
那么有没有既能节约时间⏱️又能节省流量📉的图片加载方案呢?当然有啦!🎉 那就是使用渐进式图片!💡
🌟 关键点总结:
传统加载:白屏等待 → 体验差渐进式加载:模糊→清晰 → 体验优- 优势:省时 + 省流量 = 双赢!
对比普通和渐进 🆚
网络不好时,或者图片资源巨巨巨大时,看到感兴趣的部分,那个图片转啊转啊loading ing...。
终于等到图片加载出来了,结果这图缺点意思,心里暗骂:“不仅浪费我时间,还浪费我流量”。
普通
普通:是随着下载图片数据的完成度,逐渐从上到下显示完成的。
普通jpeg图片的压缩方式是采用从左至右、从上到下逐行压缩的
放慢动作再来一张图,(有点慢):
渐进
渐进:渐进式jpeg图片的压缩方式是根据小波变换,先存储低频(轮廓)内容,然后再存储高频(细节)内容,这样在拉取图片的过程中,就是一个逐渐清晰的过程。
也就是说,先显示图片整体的一个模糊效果,随着下载数据的增多,逐渐细化图片中的各个细节,使得图片分辨率逐渐提高,最终还原出完整的图像。
如果要针对移动网络的场景优化流量,还可以只下载渐进式图片的一部分,以达到降低图像分辨率和减少流量的目的。
就是这种慢慢从模糊变清晰的过程,这就是渐进式图片的好处。
解决 💡
方法一:利用JPG格式的渐进式特性
最简单的实现方式是直接使用支持渐进式加载的JPG图片:
<img src="progressive-image.jpg" alt="渐进式图片示例">
工作原理:
JPG格式天生就支持多帧存储🎞️- 第一帧:只包含一个低质量缩略图(先让你看个大概👀)
- 后续帧:逐步填充更高质量的图像数据📈
- 浏览器收到第一帧后,秒速显示模糊预览⚡
- 随着更多数据到达🚚,图片逐级变清晰✨(就像对焦镜头一样🔍)
优点:
- 实现极其简单,无需额外代码
- 浏览器原生支持,性能良好
缺点:
- 兼容性问题:某些旧版浏览器不支持渐进式JPG
- 依赖图片本身:需要UI设计师提供包含多帧的JPG图片,或使用专门的工具生成
方法二:自定义组件实现
当方法一不可行时(如设计师不配合、用户上传的普通图片等),我们可以通过自定义组件实现类似效果。
组件基本思路:
- 同时加载小图(模糊缩略图)和大图(高清原图)🖼️
- 初始显示小图,隐藏大图
- 监听大图的加载完成事件👂
- 大图加载完成后,显示大图并隐藏小图✨
- 添加过渡动画使切换更平滑🎬
vue写法
<template>
<div class="progressive-image">
<img
:src="placeholderSrc"
:alt="alt"
class="placeholder"
:style="{ opacity: isLoaded ? 0 : 1 }"
/>
<img
:src="src"
:alt="alt"
class="full-image"
:style="{ opacity: isLoaded ? 1 : 0 }"
@load="onImageLoad"
/>
</div>
</template>
<script setup>
import { ref } from 'vue';
const props = defineProps({
placeholderSrc: String,
src: String,
alt: String
});
const isLoaded = ref(false);
const onImageLoad = () => {
isLoaded.value = true;
};
</script>
React写法
模糊缩略图优先加载,再平滑切换到高清图
import { useState, useEffect } from 'react';
function ProgressiveImage({ placeholderSrc, src, alt, ...props }) {
const [isLoaded, setIsLoaded] = useState(false); // 标记大图是否加载完成
useEffect(() => {
const img = new Image(); // 创建一个新的图片对象用于预加载大图
img.src = src; // 设置要加载的高清图地址
img.onload = () => {
setIsLoaded(true); // 大图加载完毕后,更新状态触发组件更新
};
}, [src]);
return (
<div style={{ position: 'relative', overflow: 'hidden' }}>
{/* 👇 模糊小图:优先显示,等大图加载后隐藏 */}
<img
src={placeholderSrc}
alt={alt}
style={{
width: '100%',
height: '100%',
filter: 'blur(5px)', // 模糊效果
transition: 'opacity 0.5s ease-out', // 加入过渡动画
opacity: isLoaded ? 0 : 1, // 大图加载完成后,小图隐藏
position: isLoaded ? 'absolute' : 'relative' // 保证切换时图片位置一致
}}
{...props}
/>
{/* 👇 高清大图:初始隐藏,加载完成后显示 */}
<img
src={src}
alt={alt}
style={{
width: '100%',
height: '100%',
transition: 'opacity 0.5s ease-out', // 过渡动画
opacity: isLoaded ? 1 : 0, // 大图加载完成后才显示
position: isLoaded ? 'relative' : 'absolute' // 与小图互补,保持图层顺序
}}
{...props}
/>
</div>
);
}
// ✅ 使用方式:传入模糊小图和高清原图的路径
<ProgressiveImage
placeholderSrc="small-blurry-image.jpg"
src="large-original-image.jpg"
alt="示例图片"
/>
总结 ✨
最后总结一下,为什么前端面试,总爱,总喜欢问,性能怎么优化,各种优化。有时候可能说,说不好,或者做是做过,但是说,突然间内心翻江倒海:“死了,怎么突然间想不起几点”。
但一个东西太大,太慢,在现在这个时代,太大太慢太卡,用户不会说给你一次机会两次机会,人家直接就会走掉的,流失了,就会影响用户体验,就会直接影响公司赚钱。
我们可能想:写代码,公司按时付,没我们什么事。
用户用都不用,或者等都不等,很快这个产品就会淘汰,直接换人换产品。
渐进式图片转换
优化图片加载体验除了图片压缩到100kb并不影响效果(压缩或用webp格式)、cdn加速、用雪碧图、data-src懒加载、预加载到本地,是不是还可以说一个渐进。