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

Ilya Grigorik

WebFont "đầy đủ" bao gồm mọi biến thể kiểu cách (mà bạn có thể không cần đến) và tất cả các ký tự (có thể không được sử dụng) sẽ 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 những nội dung họ sẽ sử dụng xuống.

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

Với các 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ể bắt buộc, đồng thời tải xuống tập hợp tối thiểu cần thiết để 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

Việc tải từng phần phông chữ mang một hàm ý quan trọng ẩn giấu có thể làm chậm trễ quá trình hiển thị văn bản. Trình duyệt phải xây dựng cây hiển thị, phụ thuộc vào cây DOM và CSSOM, trước khi biết được tài nguyên phông chữ nào cần để hiển thị văn bản. Do đó, các yêu cầu phông chữ sẽ bị trì hoãn khá 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ìm nạp được tài nguyên.

Đường dẫn hiển thị quan trọng của 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à tạo DOM.
  3. Trình duyệt phát hiện CSS, JS cũng như các tài nguyên khác và gửi yêu cầu.
  4. Trình duyệt tạo CSSOM sau khi nhận 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ị.
    • Yêu cầu phông chữ được gửi đi sau khi cây hiển thị cho biết biến thể phông chữ nào cần thiết để hiển thị 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 có phông chữ, trình duyệt sẽ vẽ các pixel văn bản.

"Cuộc đua" giữa điểm vẽ đầu tiên của nội dung trang, có thể được thực hiện ngay sau khi cây hiển thị được tạo và việc yêu cầu tài nguyên phông chữ là nguyên nhân tạo ra "vấn đề văn bản trống" trong đó 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 hành vi của trình duyệt với các phông chữ không có sẵn, bạn có thể ngăn các trang trống và bố cục thay đổi do việc tải phông chữ.

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

Nếu có khả năng cao là 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 sớm trong đường dẫn hiển thị quan trọng mà không phải đợi CSSOM được tạo.

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

Mặc dù việc tải trước làm tăng khả năng WebFont sẽ hiển thị khi nội dung của một trang hiển thị, nhưng việc này không đảm bảo. 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 không hiển thị trong quá trình tải phông chữ, bạn có thể thấy hành vi mặc định của trình duyệt 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 phông chữ xuống thành ba khoảng thời gian chính:

  1. Khoảng thời gian đầu tiên là 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ông chữ đó đều phải kết xuất với mặt phông chữ dự phòng không hiển thị. 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ông chữ đó đều phải kết xuất với mặt phông chữ dự phòng. Nếu kiểu phông chữ tải thành công trong thời gian hoán đổi thì kiểu phông chữ đó sẽ được sử dụng bình thường.
  3. Giai đoạn 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, dẫn đến tình trạng dự phòng phông chữ bình 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 hiển thị phông chữ, tuỳ thuộc vào việc liệu phông chữ đó có được tải xuống hay khô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:

@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ữ

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

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 mặt 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 của chúng. 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ể, 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 của phông chữ, 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ữ tất cả các khung hiển thị 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 quá trình 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, sau đó 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à điều 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 đó, chúng lý tưởng là phù hợp để hết hạn tối đa lâu – 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 service worker, 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 là 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ó cá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 khi 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 Font: hành vi tải từng phần mặc định có thể dẫn đến chậm hiển thị văn bản. Các tính năng này của 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à hết thời gian chờ cho 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. Đảm bảo rằng máy chủ của bạn cung cấp dấu thời gian tối đa tồn tại trong thời gian 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 khác nhau. Nếu bạn sử dụng trình chạy dịch vụ, 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á quá 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: