Hình ảnh chiếm phần lớn dung lượng tải của một trang web hiện đại. Theo HTTP Archive, trung bình hình ảnh chiếm khoảng 50% tổng dung lượng của một trang web. Việc tối ưu hóa hình ảnh không chỉ giúp trang web tải nhanh hơn mà còn cải thiện đáng kể trải nghiệm người dùng, đặc biệt là trên các thiết bị di động và kết nối mạng chậm.

Trong bài viết này, mình sẽ chia sẻ các kỹ thuật tối ưu hóa hình ảnh hiệu quả nhất mà mình đã áp dụng trong các dự án thực tế.

1. Chọn định dạng hình ảnh phù hợp

Mỗi định dạng hình ảnh có những ưu và nhược điểm riêng, phù hợp với các trường hợp sử dụng khác nhau:

JPEG

  • Phù hợp cho: Hình ảnh thực tế, ảnh chụp, hình ảnh có nhiều màu sắc và chi tiết
  • Ưu điểm: Kích thước file nhỏ, hỗ trợ rộng rãi
  • Nhược điểm: Nén lossy (mất dữ liệu), không hỗ trợ trong suốt

PNG

  • Phù hợp cho: Hình ảnh cần độ trong suốt, đồ họa với ít màu sắc, logo
  • Ưu điểm: Nén lossless (không mất dữ liệu), hỗ trợ trong suốt
  • Nhược điểm: Kích thước file lớn hơn JPEG

WebP

  • Phù hợp cho: Thay thế cả JPEG và PNG trong hầu hết các trường hợp
  • Ưu điểm: Kích thước file nhỏ hơn 25-35% so với JPEG, hỗ trợ cả nén lossy và lossless, hỗ trợ trong suốt
  • Nhược điểm: Không được hỗ trợ trên một số trình duyệt cũ

AVIF

  • Phù hợp cho: Thay thế WebP, JPEG, PNG khi cần tối ưu kích thước tối đa
  • Ưu điểm: Kích thước file nhỏ hơn 50% so với JPEG, chất lượng hình ảnh tốt hơn
  • Nhược điểm: Hỗ trợ trình duyệt còn hạn chế, thời gian mã hóa lâu

SVG

  • Phù hợp cho: Đồ họa vector, logo, biểu tượng, hình minh họa đơn giản
  • Ưu điểm: Có thể mở rộng không giới hạn mà không mất chất lượng, kích thước file nhỏ cho đồ họa đơn giản
  • Nhược điểm: Không phù hợp cho hình ảnh phức tạp, ảnh chụp

2. Sử dụng thẻ <picture> và định dạng hiện đại

Thẻ <picture> cho phép bạn cung cấp nhiều phiên bản của cùng một hình ảnh trong các định dạng khác nhau, và trình duyệt sẽ chọn định dạng phù hợp nhất mà nó hỗ trợ:

<picture>
  <source srcset="image.avif" type="image/avif" />
  <source srcset="image.webp" type="image/webp" />
  <img src="image.jpg" alt="Mô tả hình ảnh" width="800" height="600" />
</picture>

Trong ví dụ trên:

  • Trình duyệt hỗ trợ AVIF sẽ tải file AVIF
  • Trình duyệt không hỗ trợ AVIF nhưng hỗ trợ WebP sẽ tải file WebP
  • Trình duyệt không hỗ trợ cả hai sẽ sử dụng JPEG làm fallback

3. Responsive images với srcset và sizes

Sử dụng thuộc tính srcsetsizes để cung cấp nhiều phiên bản hình ảnh với kích thước khác nhau, giúp trình duyệt chọn hình ảnh phù hợp nhất dựa trên kích thước màn hình và mật độ điểm ảnh:

<img
  src="image-800w.jpg"
  srcset="image-400w.jpg 400w, image-800w.jpg 800w, image-1200w.jpg 1200w"
  sizes="(max-width: 600px) 400px,
            (max-width: 1200px) 800px,
            1200px"
  alt="Mô tả hình ảnh"
  width="800"
  height="600"
/>

4. Lazy loading

Lazy loading là kỹ thuật chỉ tải hình ảnh khi chúng sắp hiển thị trong viewport, giúp giảm thời gian tải trang ban đầu và tiết kiệm băng thông:

<img
  src="image.jpg"
  loading="lazy"
  alt="Mô tả hình ảnh"
  width="800"
  height="600"
/>

Hầu hết các trình duyệt hiện đại đều hỗ trợ thuộc tính loading="lazy" native. Đối với các trình duyệt cũ hơn, bạn có thể sử dụng Intersection Observer API:

document.addEventListener("DOMContentLoaded", function () {
  const lazyImages = document.querySelectorAll("img.lazy");

  if ("IntersectionObserver" in window) {
    const imageObserver = new IntersectionObserver(function (
      entries,
      observer
    ) {
      entries.forEach(function (entry) {
        if (entry.isIntersecting) {
          const image = entry.target;
          image.src = image.dataset.src;
          image.classList.remove("lazy");
          imageObserver.unobserve(image);
        }
      });
    });

    lazyImages.forEach(function (image) {
      imageObserver.observe(image);
    });
  }
});

5. Nén và tối ưu hóa hình ảnh

Nén hình ảnh

Nén hình ảnh là cách hiệu quả nhất để giảm kích thước file. Có hai loại nén:

  • Nén lossy: Giảm kích thước bằng cách loại bỏ một số dữ liệu hình ảnh (JPEG, WebP lossy)
  • Nén lossless: Giảm kích thước mà không làm mất dữ liệu (PNG, WebP lossless)

Các công cụ nén hình ảnh hiệu quả:

  • TinyPNG: Nén PNG và JPEG
  • Squoosh: Công cụ nén đa định dạng của Google
  • ImageOptim: Ứng dụng desktop cho macOS
  • MozJPEG: Trình mã hóa JPEG tối ưu
  • AVIF.io: Chuyển đổi và nén sang định dạng AVIF

Tự động hóa với build tools

Tự động hóa quá trình tối ưu hình ảnh trong quy trình CI/CD:

// Ví dụ với webpack và image-webpack-loader
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|webp|avif|svg)$/i,
        use: [
          {
            loader: "file-loader",
            options: {
              name: "[name].[ext]",
              outputPath: "images/",
            },
          },
          {
            loader: "image-webpack-loader",
            options: {
              mozjpeg: {
                progressive: true,
                quality: 75,
              },
              optipng: {
                enabled: true,
              },
              pngquant: {
                quality: [0.65, 0.9],
                speed: 4,
              },
              webp: {
                quality: 75,
              },
            },
          },
        ],
      },
    ],
  },
};

6. Sử dụng CDN và Image Service

Các dịch vụ CDN chuyên biệt cho hình ảnh như Cloudinary, Imgix, hay Cloudflare Images có thể tự động tối ưu hóa, thay đổi kích thước và phân phối hình ảnh của bạn:

<!-- Ví dụ với Cloudinary -->
<img
  src="https://res.cloudinary.com/demo/image/upload/f_auto,q_auto,w_800/sample.jpg"
  alt="Mô tả hình ảnh"
  width="800"
  height="600"
/>

Trong URL trên:

  • f_auto: Tự động chọn định dạng tốt nhất (WebP, AVIF) dựa trên trình duyệt
  • q_auto: Tự động điều chỉnh chất lượng tối ưu
  • w_800: Thay đổi kích thước hình ảnh thành chiều rộng 800px

7. Tránh CLS (Cumulative Layout Shift)

CLS là một trong những Core Web Vitals của Google, đo lường mức độ ổn định bố cục của trang. Để tránh CLS do hình ảnh:

  1. Luôn chỉ định kích thước hình ảnh: Thêm thuộc tính widthheight cho tất cả các thẻ <img>:
<img src="image.jpg" alt="Mô tả hình ảnh" width="800" height="600" />
  1. Sử dụng aspect-ratio trong CSS:
img {
  max-width: 100%;
  height: auto;
  aspect-ratio: attr(width) / attr(height);
}
  1. Sử dụng placeholder hoặc skeleton:
<div
  class="image-container"
  style="aspect-ratio: 4/3; background-color: #f0f0f0;"
>
  <img
    src="image.jpg"
    alt="Mô tả hình ảnh"
    loading="lazy"
    width="800"
    height="600"
  />
</div>

8. Tối ưu hóa hình ảnh cho Core Web Vitals

Largest Contentful Paint (LCP)

LCP đo thời gian tải và hiển thị phần tử lớn nhất trong viewport, thường là hình ảnh hero:

  1. Ưu tiên tải hình ảnh quan trọng:
<link rel="preload" href="hero-image.jpg" as="image" />
  1. Sử dụng LQIP (Low Quality Image Placeholder):
<style>
  .hero-img {
    background-image: url("hero-tiny.jpg");
    background-size: cover;
  }
</style>
<div class="hero-img">
  <img src="hero.jpg" alt="Hero image" width="1200" height="600" />
</div>
  1. Cân nhắc sử dụng CSS thay cho hình ảnh khi có thể (gradient, pattern, etc.)

9. Tối ưu hóa SVG

SVG là định dạng vector tuyệt vời cho logo và icon, nhưng cũng cần được tối ưu:

  1. Sử dụng công cụ như SVGO:
npx svgo -f src/images/ -o dist/images/
  1. Nhúng SVG trực tiếp vào HTML để tiết kiệm request HTTP:
<svg width="24" height="24" viewBox="0 0 24 24">
  <path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"></path>
</svg>
  1. Sử dụng SVG sprite để tái sử dụng icon:
<svg>
  <defs>
    <g id="icon-home">
      <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"></path>
    </g>
    <!-- Thêm các icon khác -->
  </defs>
</svg>

<!-- Sử dụng icon -->
<svg><use href="#icon-home"></use></svg>

10. Theo dõi và đo lường hiệu suất

Theo dõi hiệu suất hình ảnh của bạn với các công cụ:

  • Lighthouse: Kiểm tra và đưa ra đề xuất cải thiện
  • WebPageTest: Phân tích chi tiết việc tải hình ảnh
  • Chrome DevTools: Xem kích thước, thời gian tải của từng hình ảnh
  • Core Web Vitals report trong Google Search Console

Kết luận

Tối ưu hóa hình ảnh là một trong những cách hiệu quả nhất để cải thiện hiệu suất trang web. Bằng cách áp dụng các kỹ thuật trên, bạn có thể giảm đáng kể thời gian tải trang, cải thiện trải nghiệm người dùng và thậm chí cải thiện thứ hạng SEO.

Hãy nhớ rằng không có giải pháp “một kích cỡ phù hợp với tất cả” - chiến lược tối ưu hóa hình ảnh tốt nhất sẽ phụ thuộc vào nhu cầu cụ thể của dự án và đối tượng người dùng của bạn. Thử nghiệm và đo lường là chìa khóa để tìm ra chiến lược tối ưu nhất cho trang web của bạn.