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 srcset
và sizes
để 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ệtq_auto
: Tự động điều chỉnh chất lượng tối ưuw_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:
- Luôn chỉ định kích thước hình ảnh: Thêm thuộc tính
width
vàheight
cho tất cả các thẻ<img>
:
<img src="image.jpg" alt="Mô tả hình ảnh" width="800" height="600" />
- Sử dụng aspect-ratio trong CSS:
img {
max-width: 100%;
height: auto;
aspect-ratio: attr(width) / attr(height);
}
- 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:
- Ưu tiên tải hình ảnh quan trọng:
<link rel="preload" href="hero-image.jpg" as="image" />
- 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>
- 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:
- Sử dụng công cụ như SVGO:
npx svgo -f src/images/ -o dist/images/
- 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>
- 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.