Tối ưu hoá việc tải và hiển thị WebFont

Ilya Grigorik
Ilya Grigorik

WebFont "đầy đủ" bao gồm tất cả biến thể kiểu cách mà có thể bạn không cần, cùng với tất cả ký tự (có thể không được sử dụng) có thể dễ dàng dẫn đến việc tải xuống nhiều megabyte. Trong bài đăng này, bạn sẽ tìm hiểu cách tối ưu hoá việc tải WebFonts để khách truy cập chỉ tải nội dung họ sẽ sử dụng xuống.

Để giải quyết vấn đề các tệp lớn chứa tất cả biến thể, quy tắc CSS @font-face được thiết kế riêng để cho phép bạn chia bộ phông chữ thành một tập hợp tài nguyên. Ví dụ: tập hợp con Unicode và các biến thể kiểu riêng biệt.

Với những nội dung khai báo này, trình duyệt sẽ tìm ra các tập hợp con và biến thể cần thiết, đồng thời tải tập hợp tối thiểu cần thiết xuống để hiển thị văn bản. Điều này rất thuận tiện. Tuy nhiên, nếu bạn không cẩn thận, việc này cũng có thể tạo ra nút thắt cổ chai về hiệu suất trong đường dẫn hiển thị quan trọng và trì hoãn việc hiển thị văn bản.

Hành vi mặc định

Tính năng tải từng phần phông chữ mang ý nghĩa quan trọng ẩn giấu ngụ ý quan trọng có thể làm chậm quá trình hiển thị văn bản. Trình duyệt phải tạo cây hiển thị, tuỳ thuộc vào cây DOM và CSSOM, trước khi biết tài nguyên phông chữ nào trình duyệt cần để hiển thị văn bản. Do đó, các yêu cầu phông chữ bị trì hoãn lâu sau các tài nguyên quan trọng khác và trình duyệt có thể bị chặn hiển thị văn bản cho đến khi tài nguyên được tìm nạp.

Đường dẫn hiển thị quan trọng về phông chữ

  1. Trình duyệt yêu cầu tài liệu HTML.
  2. Trình duyệt bắt đầu phân tích cú pháp phản hồi HTML và xây dựng DOM.
  3. Trình duyệt sẽ phát hiện CSS, JS và các tài nguyên khác cũng như các yêu cầu gửi đi.
  4. Trình duyệt sẽ tạo CSSOM sau khi nhận được tất cả nội dung CSS và kết hợp CSS đó với cây DOM để tạo cây hiển thị.
    • Các yêu cầu phông chữ sẽ được gửi đi sau khi cây hiển thị cho biết cần có biến thể phông chữ nào để kết xuất văn bản được chỉ định trên trang.
  5. Trình duyệt thực hiện bố cục và vẽ nội dung lên màn hình.
    • Nếu chưa có phông chữ, trình duyệt có thể không hiển thị bất kỳ pixel văn bản nào.
    • Sau khi phông chữ có sẵn, trình duyệt sẽ vẽ các pixel văn bản.

"Cuộc đua" giữa lần hiển thị nội dung trang đầu tiên, có thể được thực hiện ngay sau khi cây hiển thị được tạo và yêu cầu về tài nguyên phông chữ sẽ tạo ra "vấn đề văn bản trống" nơi trình duyệt có thể hiển thị bố cục trang nhưng bỏ qua bất kỳ văn bản nào.

Bằng cách tải trước WebFonts và sử dụng font-display để kiểm soát cách trình duyệt hoạt động với phông chữ không có sẵn, bạn có thể ngăn các trang trống và thay đổi bố cục do việc tải phông chữ.

Tải trước tài nguyên WebFont

Nếu có nhiều khả năng trang của bạn sẽ cần một WebFont cụ thể được lưu trữ tại một URL mà bạn biết trước, bạn có thể tận dụng tính năng ưu tiên tài nguyên. Việc sử dụng <link rel="preload"> sẽ kích hoạt yêu cầu cho WebFont ngay trong đường dẫn hiển thị quan trọng mà không cần phải đợi tạo CSSOM.

Tuỳ chỉnh độ trễ hiển thị văn bản

Mặc dù việc tải trước có nhiều khả năng sẽ hiển thị WebFont khi nội dung của một trang hiển thị, nhưng việc tải trước không đảm bảo điều này. Bạn vẫn cần xem xét cách hoạt động của trình duyệt khi hiển thị văn bản sử dụng font-family (chưa có sẵn).

Trong bài đăng Tránh văn bản ẩn trong khi tải phông chữ, bạn có thể thấy hoạt động mặc định của trình duyệt là không nhất quán. Tuy nhiên, bạn có thể cho các trình duyệt hiện đại biết cách bạn muốn chúng hoạt động bằng cách sử dụng font-display.

Hỗ trợ trình duyệt

  • 60
  • 79
  • 58
  • 11,1

Nguồn

Tương tự như các hành vi hết thời gian chờ phông chữ hiện có mà một số trình duyệt triển khai, font-display phân chia thời gian tải xuống phông chữ thành 3 giai đoạn chính:

  1. Giai đoạn đầu tiên là khoảng thời gian chặn phông chữ. Trong thời gian này, nếu mặt phông chữ không được tải, thì mọi phần tử muốn sử dụng phần tử đó đều phải hiển thị bằng mặt phông chữ dự phòng ẩn. Nếu kiểu phông chữ tải thành công trong khoảng thời gian chặn, thì kiểu phông chữ đó sẽ được sử dụng bình thường.
  2. Khoảng thời gian hoán đổi phông chữ xảy ra ngay sau khoảng thời gian chặn phông chữ. Trong khoảng thời gian này, nếu mặt phông chữ không được tải, thì mọi phần tử muốn sử dụng phần tử đó đều phải hiển thị bằng mặt phông chữ dự phòng. Nếu kiểu phông chữ tải thành công trong khoảng thời gian hoán đổi, thì khi đó kiểu phông chữ đó sẽ được sử dụng bình thường.
  3. Thời gian lỗi phông chữ xảy ra ngay sau khoảng thời gian hoán đổi phông chữ. Nếu phông chữ chưa được tải khi khoảng thời gian này bắt đầu, thì phông chữ đó sẽ được đánh dấu là không tải được, khiến phông chữ dự phòng thông thường. Nếu không, phông chữ sẽ được sử dụng bình thường.

Khi hiểu rõ các khoảng thời gian này, bạn có thể sử dụng font-display để quyết định cách phông chữ hiển thị, tuỳ thuộc vào việc phông chữ đó được tải xuống hay thời điểm tải xuống.

Để làm việc với thuộc tính font-display, hãy thêm thuộc tính này vào các quy tắc @font-face của bạn:

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  font-display: auto; /* or block, swap, fallback, optional */
  src: local('Awesome Font'),
       url('/fonts/awesome-l.woff2') format('woff2'), /* will be preloaded */
       url('/fonts/awesome-l.woff') format('woff'),
       url('/fonts/awesome-l.ttf') format('truetype'),
       url('/fonts/awesome-l.eot') format('embedded-opentype');
  unicode-range: U+000-5FF; /* Latin glyphs */
}

font-display hiện hỗ trợ phạm vi giá trị sau:

  • auto
  • block
  • swap
  • fallback
  • optional

Để biết thêm thông tin về việc tải trước phông chữ và thuộc tính font-display, hãy xem các bài đăng sau:

API tải phông chữ

Khi được sử dụng cùng nhau, <link rel="preload"> và CSS font-display mang lại cho bạn nhiều quyền kiểm soát đối với việc tải và hiển thị phông chữ mà không phải tốn nhiều chi phí. Tuy nhiên, nếu cần các tuỳ chỉnh khác và sẵn sàng chịu chi phí phát sinh khi chạy JavaScript, thì bạn vẫn có một lựa chọn khác.

Font Loading API (API tải phông chữ) cung cấp giao diện tập lệnh để xác định và thao tác với các phông chữ CSS, theo dõi tiến trình tải xuống và ghi đè hành vi tải từng phần mặc định. Ví dụ: nếu chắc chắn rằng cần phải có một biến thể phông chữ cụ thể, thì bạn có thể xác định biến thể đó và yêu cầu trình duyệt bắt đầu tìm nạp ngay tài nguyên phông chữ:

Hỗ trợ trình duyệt

  • 35
  • 79
  • 41
  • 10

Nguồn

var font = new FontFace("Awesome Font", "url(/fonts/awesome.woff2)", {
  style: 'normal', unicodeRange: 'U+000-5FF', weight: '400'
});

// don't wait for the render tree, initiate an immediate fetch!
font.load().then(function() {
  // apply the font (which may re-render text and cause a page reflow)
  // after the font has finished downloading
  document.fonts.add(font);
  document.body.style.fontFamily = "Awesome Font, serif";

  // OR... by default the content is hidden,
  // and it's rendered after the font is available
  var content = document.getElementById("content");
  content.style.visibility = "visible";

  // OR... apply your own render strategy here...
});

Ngoài ra, vì có thể kiểm tra trạng thái phông chữ (thông qua phương thức check()) và theo dõi tiến trình tải xuống, nên bạn cũng có thể xác định chiến lược tuỳ chỉnh để hiển thị văn bản trên các trang của mình:

  • Bạn có thể giữ lại toàn bộ kết xuất văn bản cho đến khi có phông chữ đó.
  • Bạn có thể triển khai thời gian chờ tuỳ chỉnh cho từng phông chữ.
  • Bạn có thể sử dụng phông chữ dự phòng để bỏ chặn kết xuất và chèn một kiểu mới sử dụng phông chữ mong muốn sau khi phông chữ có sẵn.

Hơn hết, bạn cũng có thể kết hợp các chiến lược nêu trên cho nhiều nội dung trên trang. Ví dụ: bạn có thể trì hoãn việc hiển thị văn bản trên một số phần cho đến khi có phông chữ, sử dụng phông chữ dự phòng và kết xuất lại sau khi quá trình tải phông chữ xuống hoàn tất.

Lưu vào bộ nhớ đệm đúng cách là việc bắt buộc

Tài nguyên phông chữ thường là tài nguyên tĩnh không được cập nhật thường xuyên. Do đó, lựa chọn này phù hợp nhất với thời hạn sử dụng độ tuổi tối đa dài. Hãy đảm bảo bạn chỉ định cả tiêu đề ETag có điều kiệnchính sách kiểm soát bộ nhớ đệm tối ưu cho tất cả tài nguyên phông chữ.

Nếu ứng dụng web của bạn dùng trình chạy dịch vụ, thì việc phân phát tài nguyên phông chữ bằng chiến lược ưu tiên bộ nhớ đệm sẽ phù hợp với hầu hết các trường hợp sử dụng.

Bạn không nên lưu trữ phông chữ bằng localStorage hoặc IndexedDB; mỗi phông chữ đều có vấn đề riêng về hiệu suất. Bộ nhớ đệm HTTP của trình duyệt cung cấp cơ chế tốt nhất và mạnh mẽ nhất để phân phối tài nguyên phông chữ cho trình duyệt.

Danh sách kiểm tra tải WebFont

  • Tuỳ chỉnh việc tải và hiển thị phông chữ bằng <link rel="preload">, font-display hoặc API tải phông chữ: hành vi tải từng phần mặc định có thể khiến văn bản hiển thị bị trễ. Các tính năng này trên nền tảng web cho phép bạn ghi đè hành vi này cho các phông chữ cụ thể, cũng như chỉ định các chiến lược hiển thị tuỳ chỉnh và thời gian chờ cho các nội dung khác nhau trên trang.
  • Chỉ định chính sách xác thực lại và lưu vào bộ nhớ đệm tối ưu: phông chữ là các tài nguyên tĩnh được cập nhật không thường xuyên. Hãy đảm bảo máy chủ của bạn cung cấp dấu thời gian của thời gian tồn tại lâu dài và mã thông báo xác thực lại để cho phép sử dụng lại phông chữ hiệu quả giữa các trang. Nếu bạn sử dụng một trình chạy dịch vụ, thì chiến lược ưu tiên bộ nhớ đệm là phù hợp.

Kiểm thử tự động cho hành vi tải WebFont bằng Lighthouse

Lighthouse có thể giúp tự động hoá quy trình đảm bảo rằng bạn đang làm theo các phương pháp hay nhất để tối ưu hoá phông chữ trên web.

Các quy trình kiểm tra sau đây có thể giúp bạn đảm bảo rằng các trang của mình đang tiếp tục tuân thủ các phương pháp hay nhất về tối ưu hoá phông chữ trên web theo thời gian: