Hướng dẫn
Quảng cáo

Tạo hình ảnh Webp bằng PHP và mã HTML

Hướng dẫn viết code PHP để xem các định dạng ảnh JPG, PNG, GIF dưới dạng ảnh WebP

Một cách để tăng tốc độ trang web của bạn là sử dụng hình ảnh có kích thước nhỏ hơn, ngay cả lượng dữ liệu nhỏ cũng có thể tạo ra sự khác biệt rất lớn cho người dùng di động khi kết nối chậm hơn.

Các tài liệu về tốc độ trang của Google khuyên bạn nên chuyển sang định dạng ảnh webp , về cơ bản đây là một định dạng tệp khác, giống như .png hoặc .jpg, ảnh .webp thường có kích thước nhỏ hơn 4-5 lần với sự khác biệt tối thiểu hoặc không có chất lượng.

Chúng ta sẽ tạo một tập lệnh sẽ tự động tạo hình ảnh .webp từ các tệp .jpg / png / gif hiện có trên trang web và chúng tôi sẽ chỉ cho bạn cách tốt nhất để hiển thị những hình ảnh này.

Định dạng hình ảnh WebP là gì?

Một số định dạng hình ảnh nhất định yêu cầu ít dung lượng lưu trữ hơn những định dạng khác, đổi lại chất lượng hình ảnh được đánh đổi để có được hiệu suất đáng kể. Đáng chú ý nhất và được hỗ trợ rộng rãi trong số này là định dạng ảnh WebP . Nó được phát triển bởi Google và được mô tả như sau:

WebP là một định dạng hình ảnh hiện đại cung cấp khả năng nén không mất dữ liệu và mất dữ liệu vượt trội cho hình ảnh trên web.

Bạn có thể tìm hiểu thêm về cách hoạt động của WebP nếu bạn tò mò, nhưng chỉ cần nói rằng nó cung cấp chất lượng hình ảnh gần như tương đương với PNG và JPEG trong khi yêu cầu ít hơn 25–34% dung lượng .

Tối ưu hóa hình ảnh cho web bằng định dạng WebP:

  • Giảm thời gian phản hồi của máy chủ vì cần ít băng thông hơn để truyền những hình ảnh đó.
  • Cải thiện các chỉ số về hiển thị nội dung đầu tiên (FCP) và hiển thị có nội dung lớn nhất (LCP) của Lighthouse.
  • Tôn trọng băng thông của người dùng, thay vì tiêu thụ một cách bất cẩn vài MB dữ liệu mạng.

Điểm cuối cùng đó đặc biệt quan trọng vì Google sử dụng tính năng ưu tiên lập chỉ mục trên thiết bị di động để xếp hạng trang web của bạn và nhiều gói di động bị hạn chế ở tốc độ 3G. Cải thiện Tốc độ tải trang của bạn có thể mang lại cho người dùng trải nghiệm di động tốt hơn và có khả năng cải thiện xếp hạng của bạn trên Google.

Tất nhiên, có nhiều chỉ số Lighthouse khác mà bạn sẽ muốn xem xét khi tối ưu hóa hình ảnh cho web. Tốc độ tải trang chỉ là một trong những yếu tố như vậy.

Tất cả các trình duyệt chính đều hỗ trợ WebP, vì vậy không có lý do gì để không sử dụng nó.

Cài đặt các chương trình máy chủ chuyển đổi hình ảnh sang .webp

Trên máy chủ của bạn, bạn có thể chuyển đổi hình ảnh sang webp với cwebp gif2webp

Bạn có thể cài đặt chúng bằng yum:

Ví dụ

yum install libwebp.x86_64
yum install libwebp-tools.x86_64

Tạo thư mục chứa ảnh WebP

Tạo một thư mục trống có tên "webp" bên trong thư mục gốc trang web của bạn

Chỉnh sửa cấu hình .htaccess

Thêm các dòng mới này vào tệp .htaccess của bạn

Ví dụ

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^webp/(.*)\.webp?$ webp_generator.php?file=$1 [QSA]


Trước tiên, mã htaccess sẽ kiểm tra xem tệp hình ảnh webp đã được tạo chưa, nếu có thì nó sẽ tự động hiển thị, bỏ qua tập lệnh.

Viết code PHP tự động tạo hình ảnh

Tạo tệp tự động tạo hình ảnh webp bên trong thư mục /webp
Tạo một tệp có tên webp_generator.php và đặt nó vào thư mục gốc của trang web của bạn, dán mã tiếp theo vào đó.

Nếu bây giờ bạn có hình ảnh <strong>/images/landscape.jpg</strong> , bạn sẽ có thể truy cập tệp webp có tên <strong>/webp/images/landscape.jpg.webp</strong>

Mã này khá nhanh, một hình ảnh được tạo sẽ được tải trực tiếp khi bỏ qua tập lệnh vào lần sau

 

Ghi chú: Tập lệnh được tạo để xóa hình ảnh khỏi /webp 30 ngày một lần (xem phần ghi chú), vì vậy KHÔNG lưu trữ hình ảnh vĩnh viễn ở đó mà bạn có thể cần. Chỉ coi thư mục /webp như một thư mục bộ nhớ cache tạm thời

Ví dụ

<?php
// Lấy đường dẫn tuyệt đối
$settings_document_root = dirname(__FILE__);
$file = trim(strip_tags($_GET['file']));
// thoát ra nếu không tìm thấy tệp GỐC
if(!is_file($file)){
  
  // include("404.php");
  echo "không tìm thấy tệp gốc";
  exit;
}
// phát hiện xem tệp có phải là png / jpg / gif hay không, đối với gif, chúng ta sử dụng lệnh gif2webp
$file_extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
// mkdir -p để tạo các thư mục cha nếu cần (ví dụ: một đường dẫn đầy đủ của các thư mục con)
exec("mkdir -p ".escapeshellarg("webp/".dirname($file)));

// Chuyển đổi png, jpg
if($file_extension=="png" or $file_extension=="jpg"){
  exec("cwebp -q 80 ".escapeshellarg($settings_document_root."/".$file)." -o ".escapeshellarg($settings_document_root."/webp/".$file.".webp"));
}
// Chuyển đổi gif
if($file_extension=="gif"){
  exec("gif2webp -q 80 ".escapeshellarg($settings_document_root."/".$file)." -o ".escapeshellarg($settings_document_root."/webp/".$file.".webp"));
}

// hiển thị cảnh báo nếu tệp không được tạo đúng cách, bạn có thể thay thế điều này bằng chuyển hướng header() đến hình ảnh mặc định
if(!file_exists($settings_document_root."/webp/".$file.".webp")){
  echo "không thể tạo tệp webp ".escapeshellarg("webp/".$file);
  exit;
}

// bảo trì, xóa các tệp webp cũ, sau đó xóa các thư mục trống
exec("find webp/ -type f -mtime +30 -delete");
exec("find webp/ -type d -empty -delete");

// Tiếp tục hiển thị tệp web đã tạo
// ?tim () ở đây để nó không chuyển hướng trở lại chính nó vào lần đầu tiên khi hình ảnh được tạo
// điều đó có thể gây ra vòng lặp vô hạn vì nó lưu vào bộ nhớ cache tệp dưới dạng chuyển hướng trở lại chính nó
header("Location: /webp/".$file.".webp?".time());
exit;
?>

Thay đổi mã html của bạn để hiển thị hình ảnh .webp

Không phải tất cả các trình duyệt đều hỗ trợ hình ảnh webp, nhưng mã mẫu này sẽ dự phòng thành jpg hoặc hình ảnh khác nếu trình duyệt của người dùng không hiểu hình ảnh .webp.

Một hình ảnh bình thường giống như <img src="/images/landscape.jpg"> có thể được hiển thị ở định dạng webp bằng mã tiếp theo.

Lưu ý đường dẫn bắt đầu bằng /webp và kết thúc bằng .webp , đó là tập lệnh của chúng ở trên ta tạo ra hình ảnh webp tự động

Ví dụ

<picture>
<source srcset="/webp/images/landscape.jpg.webp" type="image/webp">
<img src="/images/landscape.jpg">
</picture>

Tối ưu hóa hình ảnh cho web với WebP và tải chậm (Lazy loading)

Giả sử bạn có một trang với khoảng 15–20 hình ảnh. Bất kể bạn tối ưu hóa những hình ảnh này với WebP đến mức nào, bạn sẽ đạt đến mức lợi nhuận giảm dần, nơi số lượng và kích thước tuyệt đối của hình ảnh của bạn sẽ lớn hơn hiệu suất đạt được khi sử dụng tính năng nén WebP.

Vậy, bạn có thể làm gì? Một chiến lược phổ biến trên các nền tảng blog như Medium - và tôi sử dụng trên trang web của riêng mình - được gọi là tải chậm (Lazy loading), trong đó hình ảnh chưa hiển thị trong khung nhìn của người dùng sẽ không được tải cho đến khi người dùng cuộn đến chúng. Bằng cách đó, khi trang tải ban đầu, băng thông được sử dụng được giới hạn ở mức chỉ vài kB.

Có hai cách để bạn có thể tải hình ảnh một cách lười biếng trong các trình duyệt hiện đại:

  1. Sử dụng thuộc tính loading="lazy", được hỗ trợ bởi tất cả các trình duyệt chính.
  2. Sử dụng IntersectionObserverAPI và một số JavaScript tùy chỉnh.

Điều quan trọng cần lưu ý là chúng KHÔNG loại trừ lẫn nhau — bạn có thể sử dụng cả hai.

Lazy loading tự nhiên

Thuộc tính loading="lazy" này cung cấp tính năng tải từng phần riêng cho hình ảnh trong trình duyệt Chromium và trong Firefox. Nó cho trình duyệt biết khi nào bắt đầu tải hình ảnh, cho phép bạn trì hoãn các yêu cầu mạng cho đến một thời điểm sau đó.

Nói tóm lại, hình ảnh có thuộc tính loading="lazy" sẽ không kích hoạt yêu cầu HTTP cho đến khi chúng cách khung nhìn một khoảng cách nhất định . Trong Chrome, khoảng cách đó là 1250px kết nối ổn định và  2500px với kết nối 3G chậm.

API IntersectionObserver

Tùy chọn thứ hai là sử dụng API IntersectionObserver, cho phép bạn phát hiện khi một phần tử đang giao nhau với khung nhìn của trình duyệt và chạy một số mã để phản hồi. Chúng tôi có thể tận dụng API này để triển khai giải pháp tải chậm tùy chỉnh, trong đó mỗi hình ảnh tải một trình giữ chỗ ban đầu, sau đó được thay thế bằng hình ảnh thực (được lưu trữ tạm thời trong một thuộc tính data-) khi nó giao với chế độ xem.

Ví dụ: đánh dấu đã sửa đổi của bạn có thể trông giống như thế này. Lưu ý cách trỏ srcset và trỏ src tới hình ảnh chỗ dành sẵn, trong khi data-srcsetdata-src trỏ tới hình ảnh WebP và JPEG thực, tương ứng.

Ví dụ

<picture class="lazy-picture">
  <source
    srcset="/path/to/img-placeholder.webp"
    data-srcset="/path/to/img.webp"
    type="image/webp">
  <img
    src="/path/to/img-placeholder.jpeg"
    data-src="/path/to/img.jpeg"
    alt="Your image's alt"
    loading="lazy">
</picture>


Tôi đang đặt tên cho các thuộc tính này data-srcsetdata-src tương ứng, nhưng bạn có thể đặt tên cho chúng bất cứ thứ gì bạn muốn vì chúng chỉ là các thuộc tính tùy chỉnh data.

Tiếp theo, chúng tôi sẽ tạo một phiên bản IntersectionObserver và sử dụng nó để phát hiện khi hình ảnh của chúng tôi giao nhau với khung nhìn của trình duyệt:

Ví dụ

const imgObserver = new IntersectionObserver((entries, self) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      lazyLoad(entry.target);
      self.unobserve(entry.target);
    }
  });
});
document.querySelectorAll('.lazy-picture').forEach((picture) => {
  imgObserver.observe(picture);
});


Và đây là cách bạn có thể triển khai hàm lazyload:

Ví dụ

const lazyLoad = (picture) => {
  const img = picture.querySelector('img');
  const sources = picture.querySelectorAll('source');

  sources.forEach((source) => {
    source.srcset = source.dataset.srcset;
    source.removeAttribute('data-srcset');
  });
  img.src = img.dataset.src;
  img.removeAttribute('data-src');
}

Bây giờ, khi người dùng cuộn trên trang web của bạn và chế độ xem giao với hình ảnh, các thuộc tính src srcset sẽ được thay thế bằng các thuộc tính data-. Thao tác này sẽ bắt đầu các yêu cầu mạng mới để tìm nạp hình ảnh có độ phân giải cao hơn, hoán đổi chúng.

Lưu ý rằng hầu hết các hướng dẫn tải chậm sẽ đặt các thuộc tính srcsrcset là các chuỗi trống. Vì vậy, họ sẽ hiển thị cho bạn một cái gì đó như thế này để đánh dấu:

Ví dụ

<img
  src=""
  data-src="/path/to/img.jpeg"
  alt="Your image's alt">


Đừng làm điều này ! Nếu bạn hiển thị thẻ hình ảnh mà không có thuộc tính src hoặc source các thẻ không có thuộc tính srcset, bạn sẽ gặp phải hai vấn đề:

  • Một sự thay đổi bố cục . Khi hình ảnh cuối cùng được tải vào, nó sẽ chuyển văn bản và bất kỳ nội dung nào sau nó xuống dưới vì hình ảnh không có thuộc tính src có mô hình hộp thu gọn không chiếm dung lượng. Điều này có thể ảnh hưởng đến điểm số thay đổi bố cục tích lũy (CLS) của bạn và không phải là trải nghiệm người dùng tuyệt vời.
  • Lỗi xác thực HTML . Mỗi thẻ phải có một đường dẫn src hợp lệ!

Thay vào đó, bạn muốn sử dụng hình ảnh giữ chỗ tạm thời. Đây có thể là trình giữ chỗ mờ — được gọi là trình giữ chỗ hình ảnh chất lượng thấp ( low-quality image placeholder) (LQIP) —đó là hình ảnh gốc nhưng được thu nhỏ xuống độ phân giải rất thấp. Vì có ít pixel hơn để làm việc, hình ảnh cuối cùng bị mờ, với các mảng màu gần giống với hình dạng của hình ảnh gốc. Sau đó, khi khung nhìn giao với phần tử, bạn tải vào hình ảnh thực bằng JavaScript. Đây chính xác là những gì chúng tôi đã làm trong đoạn mã trên.

Trong khi sử dụng lazy loading thì bạn cần sử dụng JS, vậy nếu trình duyệt không hỗ trợ Javascript thì sao? Hãy xem bài cách xử lý tải chậm (lazy loading) với trình duyệt không hỗ trợ javascript

Bài viết này đã giúp ích cho bạn?

Bài viết mới

Advertisements