Skip to content
扫码开始移动端阅读

浅谈图片优化

934
需要≈
4.67
分钟
奇淫技巧
web

思考

在web应用中,我们常常会遇到图片加载过慢的问题,现在市面上的解决方案已经非常成熟了。我这边就先结合前人的思考,谈谈自己的一些想法。如果有什么错误,欢迎指正。

方案列表

CDN

首先说一下最简单的方案,那就是使用CDN。专业的事情交给专业的人,CDN(Content Delivery Network)为网站提供内容分发网络,把图片等静态资源放到CDN上,然后直接使用CDN上的资源。

优点

  • 🚀 提升速度:可以降低自己服务器的压力,同时也可以提升访问速度。
  • 稳定性强:虽然有时CDN会抽风,但总体上要比自建服务更稳妥一些。

缺点

  • 📝 备案要求:CDN需要备案才能加速国内用户体验。
  • 💰 费用问题:免费额度有限,访问量大时可能需要防盗链等措施来控制成本。

图片转换

图片转换是图片优化的常用手段,通过压缩、格式转换等方式来减少图片体积。

📷 WebP

WebP格式是谷歌推出的一种图片格式,支持有损压缩和无损压缩。有损压缩体积小但会降低图片质量。

🖼️ SVG

SVG是矢量图,可以放大缩小而不会失真。浏览器支持SVG格式,但IE不支持。

🔧 压缩图片

通过降低分辨率、颜色数等方式减少图片体积。优点是节省带宽和存储,提升加载速度。缺点是图片质量降低,且对用户上传图片可能增加开发复杂度。

🌈 雪碧图(CSS Sprite)

雪碧图把多张图片合并成一张,通过CSS的background-position定位,减少请求次数。

优点

  • 🔍 减少请求:减少请求次数,提升访问速度。

缺点

  • ⚠️ 定位麻烦:定位麻烦,图片大小和背景色需要一致。

  • 📉 优势减弱:现在HTTP/2支持多路复用,雪碧图的优势减弱。

预加载和懒加载(lazy loading / pre-load)

预加载和懒加载常用于图片资源加载。

🚀 预加载

提前加载图片并缓存,适用于漫画和视差动画等场景,提升用户体验。

💤 懒加载

等图片出现在用户视野时才加载,适用于图片数量多的场景,如新闻和博客。虽耗费带宽,但能提升用户体验。

渐进式加载(Progressive Loading)

渐进式加载先显示大致轮廓,再逐步变清晰,提升用户体验。

🎨 我博客正在用的方案

js
import sharp from 'sharp';
import { globby } from 'globby';
import * as fs from 'fs-extra';
import * as path from 'path';
const PATH = 'public/assets/images/**/*.{jpg,png}';

/**
 * 处理图片,将其转为渐进式,并替换原文件
 * @param {string} filePath - 输入文件的路径
 */
const updateProgressive = async (filePath)=> {
  try {
    const dir = path.dirname(filePath);
    const ext = path.extname(filePath).toLowerCase();
    const baseName = path.basename(filePath, ext);
    const newFileName = `${baseName}_progressive${ext}`;
    const tempFilePath = path.join(dir, newFileName);
    if (ext === '.jpg' || ext === '.jpeg') {
      await sharp(filePath).jpeg({ progressive: true }).toFile(tempFilePath);
    } else if (ext === '.png') {
      await sharp(filePath).png({ progressive: true }).toFile(tempFilePath);
    } else {
      throw new Error(`未知格式的图片: ${ext}`);
    }

    await fs.remove(filePath);
    await fs.move(tempFilePath, filePath);
    console.log(`更新成功: ${filePath}`);
  } catch (error) {
    console.error(`更新失败 文件 ${filePath}:`, error);
  }
}

export const progressive = async () => {
  const list = await globby(PATH)
  return list.forEach(async (item) => {
    return await updateProgressive(item);
  });
};

这玩意的缺点

  • ⚠️ 兼容性问题:目前svg,webp等格式图片是没有办法支持的。
  • 🚧 开发复杂度:需要额外处理图片格式,且需要额外安装依赖。

总结

如果你有更好的解决方案,欢迎留言指出~

上次更新: