🚀 🚀 🚀 渐进式:优化图片加载体验

481 阅读5分钟

图片加载体验 🚀

渐进式图片是一种优化网页图片加载体验的技术。当页面中的图片较大时,传统的加载方式会让用户看到一片空白(白屏😣),直到图片完全加载完成才能显示。

而渐进式图片则先显示一个模糊缩略图👀,随着图片数据的逐步加载,图片会变得越来越清晰✨。

渐进式图片,我们可能或多或少见过的——页面上有个模糊的图片,然后逐渐变得清晰。这种效果是不是很神奇呢?🤔

这种做法就是,当页面上有一些图片资源比较大的时候,传统方式需要用户盯着白屏⏳等待很久,体验感非常不好😞。

那么有没有既能节约时间⏱️又能节省流量📉的图片加载方案呢?当然有啦!🎉 那就是使用渐进式图片!💡


🌟 关键点总结

  • 传统加载:白屏等待 → 体验差
  • 渐进式加载:模糊→清晰 → 体验优
  • 优势:省时 + 省流量 = 双赢

对比普通和渐进 🆚

网络不好时,或者图片资源巨巨巨大时,看到感兴趣的部分,那个图片转啊转啊loading ing...。

终于等到图片加载出来了,结果这图缺点意思,心里暗骂:“不仅浪费我时间,还浪费我流量”。

普通

普通:是随着下载图片数据的完成度,逐渐从上到下显示完成的。

普通jpeg图片的压缩方式是采用从左至右、从上到下逐行压缩的

1.gif

放慢动作再来一张图,(有点慢):

11.gif

渐进

渐进:渐进式jpeg图片的压缩方式是根据小波变换,先存储低频(轮廓)内容,然后再存储高频(细节)内容,这样在拉取图片的过程中,就是一个逐渐清晰的过程。

也就是说,先显示图片整体的一个模糊效果,随着下载数据的增多,逐渐细化图片中的各个细节,使得图片分辨率逐渐提高,最终还原出完整的图像。

如果要针对移动网络的场景优化流量,还可以只下载渐进式图片的一部分,以达到降低图像分辨率和减少流量的目的。

11.gif

就是这种慢慢从模糊变清晰的过程,这就是渐进式图片的好处。

解决 💡

方法一:利用JPG格式的渐进式特性

最简单的实现方式是直接使用支持渐进式加载的JPG图片:

<img src="progressive-image.jpg" alt="渐进式图片示例">

工作原理

  • JPG格式天生就支持多帧存储🎞️
  • 第一帧:只包含一个低质量缩略图(先让你看个大概👀)
  • 后续帧:逐步填充更高质量的图像数据📈
  • 浏览器收到第一帧后,秒速显示模糊预览⚡
  • 随着更多数据到达🚚,图片逐级变清晰✨(就像对焦镜头一样🔍)

优点

  • 实现极其简单,无需额外代码
  • 浏览器原生支持,性能良好

缺点

  1. 兼容性问题:某些旧版浏览器不支持渐进式JPG
  2. 依赖图片本身:需要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懒加载预加载到本地,是不是还可以说一个渐进