Tối ưu hóa hình ảnh cho trang web
Bài đăng này đã không được cập nhật trong 6 năm
TL;DR: bạn lười đọc? Không sao, click vào đây
Tối ưu hóa hình ảnh thì làm gì?
- Tốc độ tải trang của 1 trang web thì phụ thuộc vào nhiều yếu tố, từ cấu hình server, nơi đặt server, code có xịn hay lởm, rồi thì js, css thế nào ra sao. Ngoài ra, còn có "độ nặng" của các hình ảnh (icon, ảnh trong assets, ảnh người dùng upload,...) cũng ảnh hưởng đến tốc độ tải trang.
- Tối ưu hóa là làm những công việc đại loại như giảm kích thước (dimension) hoặc kích thước (size) của tệp hình ảnh, hoặc làm các công việc khác. Cụ thể sẽ được trình bày ở phía sau.
Lợi ích của việc tối ưu hóa hình ảnh
Tất nhiên thì có lợi thì mới làm rồi, không thì cũng không rảnh:
- Cải thiện tốc độ tải trang: Nếu trang của chúng ta mất quá nhiều thời gian để tải, người dùng có thể cảm thấy khó chịu vì phải chờ đợi và chuyển sang một thứ khác hay ho hơn.
- Giúp cải thiện SEO: Các tệp lớn làm chậm trang web và các công cụ tìm kiếm thì "ghét" các trang web chậm. Google sẽ thu thập thông tin và lập chỉ mục hình ảnh trong trang web của chúng ta nhanh hơn cho tìm kiếm hình ảnh. (Xem thêm How to Check Image Traffic in Google Analytics)
- Tạo bản sao lưu sẽ nhanh hơn. (push lên git ấy :v)
- Kích thước file hình ảnh nhỏ hơn thì việc sử dụng băng thông sẽ ít hơn. Lấy 1 ví dụ, ảnh gốc 590 KB, sau khi nén còn 151 KB, giảm 439KB, và ảnh này là 1 trong số những bức ảnh nằm trên 1 trang của dân trí với mức truy cập 100 triệu lượt 1 tuần => tiết kiệm được 43.9TB băng thông 1 tuần cho 1 bức ảnh (tính đúng không nhỉ? sao mà to vãi thế @@) ờ đấy đại loại là tiết kiệm băng thông.
- Cần dung lượng lưu trữ ít hơn trên server.
Cách tối ưu hóa hình ảnh
Chọn định dạng file phù hợp
Về cơ bản, có ba định dạng phổ biến nên được sử dụng: JPEG, PNG và GIF.
JPG
- JPG (còn được gọi là JPEG) là loại tệp phổ biến nhất cho hình ảnh trên web. JPG là hoàn hảo cho các bức ảnh bình thường hoặc các hình ảnh phức tạp chứa nhiều màu sắc, độ bóng, độ dốc hoặc các patterns phức tạp khác.
- JPG có thể được lưu 1 bức ảnh ở chất lượng cao, chất lượng thấp hoặc vị trí trung bình (giữa cao và thấp tùy người tạo ra). Điều này cho phép ta điều chỉnh và lưu hình ảnh chính xác theo cách mà ta muốn, cân bằng chất lượng và kích thước file.
PNG
- PNG là một định dạng tệp phổ biến khác. Trong Adobe Photoshop , có tùy chọn để lưu PNG dưới định dạng PNG-8 hoặc PNG-24.
- PNG-8 có một pallet (phổ màu à hay gì đó đại loại là thể hiện được số lượng màu) màu rất hạn chế là 256 màu. Mặc dù kích thước hình ảnh nhỏ hơn, nhưng đây không phải là lựa chọn tốt cho ảnh chụp và hình ảnh phức tạp.
- PNG-24 cung cấp hình ảnh có chất lượng cao hơn nhiều nhưng cái giá phải trả là kích thước file lớn hơn.
- Tuy nhiên, người ta vẫn dùng PNG vì định dạng này có 1 thứ thú vị là
transparency
(tức là ảnh mà có nền trong suốt mà ta vẫn hay dùng đó). Đây là một trong những điểm khác biệt lớn nhất giữa PNG và JPEG.
GIF
- GIF chỉ sử dụng 256 màu.
- Đây là lựa chọn tốt nhất khi mà ta muốn có 1 tấm ảnh động.
SVG
SVG là định dạng vectơ có thể mở rộng (scalable vector format) hoạt động tốt cho logos, icons, text và hình ảnh đơn giản.
- SVG tự động mở rộng trong cả trình duyệt và công cụ chỉnh sửa ảnh.
- Google lập chỉ mục SVG, giống như cách thực hiện PNG và JPG, do đó không phải lo lắng về SEO.
- SVG theo truyền thống (tất nhiên là không phải luôn luôn) có kích thước file nhỏ hơn so với PNG hoặc JPG.
Có thể đọc thêm tại đây về SVG.
Nén ảnh
Nén hình ảnh liên quan đến việc giảm kích thước tính file mà không làm giảm đáng kể chất lượng của hình ảnh. À thì nói như vậy, nhưng mà rốt cuộc thì vẫn có 2 cách nén: lossy và lossless.
Ảnh gốc làm ví dụ: định dạng JPG - kích cỡ 590 KB
Lossy
Lossy - cách này sẽ loại bỏ một số dữ liệu bên trong image. Điều này sẽ làm suy giảm chất lượng hình ảnh, vì vậy bạn sẽ phải cẩn thận về việc giảm image đi bao nhiêu. Kích thước file có thể được giảm xuống một lượng khá lớn, nhưng bù lại hình ảnh có thể chả nhìn thấy gì. :v
Và nén bằng cách này 1 cách mạnh tay: định dạng JPG - kích cỡ 68 KB
Lossless
Lossless - đây đúng là nén dữ liệu :v và nó chả mất mát gì cả. Cách này không làm giảm chất lượng nhưng nó sẽ yêu cầu các hình ảnh phải được giải nén trước khi chúng được hiển thị.
Ví dụ ảnh gốc: 3.5MB
Ảnh được nén: 778KB
Dùng cái gì để nén?
Trong thư viện imagemagik có 1 thứ để nén, chuyển đổi định dạng image là convert:
convert INPUT.gif_or_png -strip [-resize WxH] [-alpha Remove] OUTPUT.png
Ví dụ:
Hoặc đơn giản là dùng photoshop để xuất bản lại 1 bức ảnh có mức độ thân thiện hơn đối với trang web của mình :v
Cân bằng giữa chất lượng và kích thước
Như ở trên đã nói, chúng ta có thể nén image, tuy nhiên thì nhẹ đi liền với xấu =)) cần phải cân bằng giữa nặng vừa vừa và dễ nhìn: ví dụ: Nén trung bình (chất lượng tuyệt vời) định dạng JPG - kích cỡ 151 KB
Giảm kích thước hình ảnh
Cũng là kích thước image nhưng mà ở đây mình muốn nói về dimensions - chiều rộng và dài tính bằng px của image. Giảm kích thước image cũng khiến ảnh "nhẹ" đi đôi chút.
Chúng ta có thể làm là:
- Giảm kích thước hình ảnh trước khi lưu: dùng photoshop chẳng hạn, thay đổi kích thước của image rồi mới upload (người dùng có tâm)
- Giảm kích thước hình ảnh trong khi lưu hình ảnh: việc này của chúng ta đây, mình thì thường thay đổi nó trong hàm upload image:
class ImageService
{
public static function uploadFile($image)
{
$dimension = [1920, 1080];
//....
$makeImage = Image::make($image)->orientate()->resize($dimension[0], $dimension[1])->stream();
//....
$storage->put($filePath, $makeImage->__toString(), 'public');
//....
}
}
Xóa "siêu dữ liệu" khỏi các tệp
- Một trong những cách để giảm kích thước của ảnh là xóa
metadata
khỏi các file hình ảnh trước khi tải chúng lên trang web. - Dữ liệu meta hình ảnh (hình như còn được gọi là
exif
) được lưu trữ trên bất kỳ ảnh nào và bao gồm: ngày chụp, mẫu máy ảnh, flash được sử dụng, Vị trí GPS, iso, kích thước ống kính, tốc độ màn chập v.v... - Một lý do chính đáng khác để xóa dữ liệu meta hình ảnh là vì mục đích bảo mật. Facebook nó đang làm điều đó, mọi ảnh upload lên fb thì không còn thông tin exif.
Sử dụng thumbnail
Cái này hay này, thay vì hiển thị toàn bộ image ra trang của mình, thì thay vào đó là mình sẽ dùng thumbnail (sinh ra lúc upload file, chỗ mà resize trong ví dụ trên của mình ấy) là 1 hình ảnh nhỏ hơn, người dùng muốn xem ảnh to thì phải click vào thì ảnh to mới được load ra. Nói thì dài chứ đơn giản là dùng 1 thư viện như Fancybox chẳng hạn, hoặc đơn giản hơn là làm cái link nhảy sang tab khác. Ví dụ thì như Viblo này (nhưng mà hình như cũng không dùng thumbnail thì phải)
Sử dụng text là text thay vì là text bằng hình
Nghe có vẻ lằng nhằng và khó hiểu, ý mình là ví dụ có những banner quảng cáo hay câu slogan gì gì đó, ngta thay vì viết ra, thì sẽ vẽ nhăng vẽ cuội và xuất thành 1 file image, rồi show nó ra. Thì bây giờ không nên làm thế, mà hay dùng trực tiếp là text và style lại nó bằng css chẳng hạn.
Cái này cũng khá là tốt cho SEO.
Không Scale Images
Ví dụ ta có 1 image, đặt trong thẻ img
và có set thuộc tính height
và width
nhỏ hơn kích thước thật của ảnh, với mong muốn là trông nó bé
hơn thì sẽ nhẹ
hơn, nhưng mà không phải, nó vẫn load nặng
như vậy thôi. Hoặc là làm thế với mong muốn nó nhỏ đi để làm thumbnail, nhưng không nên làm thế, mà nên tạo 1 thumbnail lúc upload và dùng cái thumbnail đó cho trường hợp này.
Kết hợp Images để tiết kiệm HTTP Requests
Cái này có vẻ khó hiểu này, đại loại là thay vì load lần lượt từng image thì ta giao lưu kết hợp nhiều image để load 1 lần cho vui, ngta gọi là multi-some. ok, đọc thêm tại đây
The Fewer Graphics the Better
Ý ở đây ngta bảo là dùng càng ít image thì càng tốt, không dùng thì cũng tốt. Thay vào đó có thể thay thế bằng cách style theo css thì tốt hơn.
Sử dụng CDN
Giống như css hay js, chúng ta cũng có thể lưu hình ảnh trên cdn và không phải quan tâm lo lắng về vùng miền lẫn tốc độ load image mỗi khi đứt cáp quang nữa, họ lo hết cho mình.
Lazy loading
Đây cũng là 1 cách hay này, tức là màn hình ở vị trí nào thì load ảnh ở vị trí đó, kéo xuống thì load tiếp ở vị trí tiếp theo. Ngày xưa mình làm Viblo cũng có áp dụng jQuery Lazy, giờ chắc đập đi làm lại hết rồi :v Yeah, thôi thì cũng có ví dụ tý code cho đỡ chán:
Thêm file html:
<body class="asyncImage" data-src="https://i.imgur.com/EWx6Ao5.jpg">
<div class="container">
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</div>
</body>
Thêm tý css:
body {
background-image: url('https://i.imgur.com/ffmMq6q.jpg');
background-repeat: no-repeat;
background-size: cover;
}
.container {
width: 700px;
margin: 0 auto;
}
Cuối cùng thêm tý js:
(() => {
'use strict';
const objects = document.getElementsByClassName('asyncImage');
Array.from(objects).map((item) => {
const img = new Image();
img.src = item.dataset.src;
img.onload = () => {
item.classList.remove('asyncImage');
return item.nodeName === 'IMG' ?
item.src = item.dataset.src :
item.style.backgroundImage = `url(${item.dataset.src})`;
};
});
})();
Các bạn paste thử vào rồi chạy xem thế nào.
Tóm lại là gì?
- Sử dụng hình ảnh vector SVG bất cứ khi nào có thể cùng với PNG và JPG.
- Sử dụng CDN để phục vụ khách hàng (có tâm) trên toàn tg.
- Xóa dữ liệu
metadata
không cần thiết. - Cắt không gian màu trắng và tạo lại nó bằng cách sử dụng CSS.
- Sử dụng hiệu ứng CSS3 càng nhiều càng tốt
- Lưu hình ảnh theo kích thước phù hợp.
- Sử dụng phông chữ web thay vì đặt văn bản trong hình ảnh.
- Giảm độ sâu bit xuống.
- Sử dụng nén mất dữ liệu (lossy) nếu có thể.
- Sử dụng GIF nếu cần ảnh động (nhưng cũng nên nén lại)
- Sử dụng PNG nếu cần chi tiết cao và độ phân giải cao
- Sử dụng JPG cho ảnh chụp thường (photo) và ảnh chụp màn hình (screenshot)
- Xóa ảnh nào đó nếu không cần nó.
- Tải hình ảnh theo cách
lazy loading
để hiển thị trang đầu tiên nhanh hơn
Kết luận
Kiến thức không tự sinh ra cũng không tự mất đi, nó chỉ chuyển hóa từ trang này sang trang khác. Bài viết được tham khảo tư liệu tại:
- https://kinsta.com/blog/optimize-images-for-web/
- http://genkihagata.com/blog/svg-vs-flat-images.html
- https://medium.com/front-end-hacking/how-to-optimize-image-loading-on-your-website-855020fb41ae
- https://developers.google.com/speed/docs/insights/OptimizeImages
- https://www.imagemagick.org/script/index.php
- https://www.abetterlemonadestand.com/optimizing-images-for-web/
Ngoài ra còn thêm các phần chém gió từ mình, do vậy có chém sai thì mọi người chém nhẹ tay, hoặc do buồn ngủ nên chém thiếu thì mọi người chém tiếp hộ mình.
Đặc biệt xin cảm ơn nhà tài trợ chính của bài viết:
techtalk có lấy bài thì ghi cả tên tớ vào nữa nhé, hôm trước các bạn lấy bài tớ còn chèn link sai vào nguồn :-s
All rights reserved