Trình duyệt luôn tải font TTF 33KB dù file WOFF2 16KB nằm ngay bên cạnh

Trình duyệt luôn tải font TTF 33KB dù file WOFF2 16KB nằm ngay bên cạnh

Bài viết do Nguyễn Nhật Ánh Dương thực hiện, biên soạn theo Chính sách nội dung của Marketing365. Cập nhật lần cuối .

Nội dung
  1. Một dòng CSS nhỏ nuốt trọn nỗ lực cắt font subset
  2. Thứ tự đọc thuộc tính src trong khai báo font-face
  3. DevTools tố cáo: 33.124 byte thay vì 13.728 byte
  4. Tự host font không có nghĩa là tự tối ưu
  5. Sửa một dấu phẩy và trật tự ba định dạng
  6. Những bẫy vô hình của cache và preload khi đổi font

Một trong những việc làm tôi tự hào nhất trong đợt audit hiệu năng hồi tháng 7 là cắt giảm thành công bộ biểu tượng Font Awesome. Từ file gốc fontawesome-webfont.woff2 nặng 77.160 byte chứa hơn 670 icon thừa thãi, tôi trích xuất đúng 103 ký tự thực sự xuất hiện trên giao diện để tạo ra bản fa4-subset.woff2 chỉ nặng 13.728 byte. Tiết kiệm hơn 82% dung lượng font.

Thế nhưng, khi mở DevTools trên một kết nối mạng 4G sạch để nghiệm thu, tôi ngỡ ngàng phát hiện trình duyệt vẫn tải về một file font nặng đúng 33.124 byte. Bản subset 13 KB của tôi nằm yên vị trên máy chủ và chưa từng được trình duyệt nào chạm tới.

Một dòng CSS nhỏ nuốt trọn nỗ lực cắt font subset

Khi kiểm tra file stylesheet tổng hợp của giao diện, tôi tìm thấy khối khai báo quy tắc @font-face dành cho font icon. Dòng lệnh đó trông vô hại như sau:

@font-face {
  font-family: 'FontAwesome';
  src: url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),
       url('../fonts/fa4-subset.woff2?v=4.7.0') format('woff2');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

Về mặt cú pháp CSS, đoạn mã trên hoàn toàn hợp lệ. Trình biên dịch không báo lỗi, trang web hiển thị đầy đủ icon, điểm giao diện không vỡ một góc nào. Nhưng về mặt hiệu năng mạng, dòng lệnh này là một thảm họa âm thầm.

Thứ tự đọc thuộc tính src trong khai báo font-face

Theo đặc tả kỹ thuật của W3C (CSS Fonts Module Level 4), thuộc tính src trong @font-face là một danh sách ưu tiên được đánh giá tuần tự từ trên xuống dưới, từ trái sang phải.

Quy trình xử lý của trình duyệt diễn ra theo từng bước nghiêm ngặt:

  • Trình duyệt đọc URL đầu tiên trong danh sách: fontawesome-webfont.ttf với định dạng format('truetype').
  • Nó tự kiểm tra: “Mình có hỗ trợ giải mã định dạng TrueType Font (.ttf) không?”. Mọi trình duyệt hiện đại (Chrome, Safari, Firefox, Edge) đều hỗ trợ TTF từ hơn 15 năm trước. Câu trả lời là CÓ.
  • Ngay lập tức, trình duyệt phát lệnh HTTP request tải file .ttf (33.124 byte) về máy và dừng duyệt danh sách src.
  • URL thứ hai chứa bản nén siêu nhẹ fa4-subset.woff2 (13.728 byte) nằm ngay bên dưới bị bỏ qua hoàn toàn.
Bảng đối chiếu thứ tự nạp font trong DevTools Network tab
Phân tích hành vi DevTools: Trình duyệt tải TTF 33 KB do đứng đầu danh sách src, bỏ qua file WOFF2 13 KB đặt phía sau (đo ngày 14/08/2026).

DevTools tố cáo: 33.124 byte thay vì 13.728 byte

Chênh lệch giữa 33.124 byte và 13.728 byte là gần 20 KB dữ liệu. Trên một kết nối cáp quang, 20 KB có thể trôi qua trong vài mili-giây. Nhưng trên mạng di động 3G/4G chập chờn:

  • File TTF không có thuật toán nén Brotli chuyên dụng như WOFF2, khiến thời gian tải tăng gấp gần 2,5 lần (48ms so với 18ms).
  • Thời gian phân tích và giải mã font thô trong bộ nhớ lâu hơn, kéo dài thời gian chặn render chữ (FOIT/FOUT).
  • Tổng dung lượng trang web phình to vô ích, làm giảm điểm tối ưu hóa trong các bài kiểm tra Core Web Vitals.

Tự host font không có nghĩa là tự tối ưu

Nhiều nhà phát triển thường nghĩ rằng chỉ cần chuyển font từ Google Fonts hoặc CDN bên ngoài về lưu trữ trực tiếp trên máy chủ (self-hosted) là đã hoàn thành tối ưu. Trường hợp này chứng minh điều ngược lại: tự host font chỉ loại bỏ kết nối DNS bên ngoài, nhưng nếu cấu hình sai trong CSS, bạn thậm chí còn làm trang web chạy chậm hơn cả việc dùng CDN chuyên dụng.

Một số theme WordPress đóng gói sẵn các file font cũ để tương thích ngược với Internet Explorer 8-11, và khi gộp file CSS, lập trình viên thường tiện tay đưa định dạng .eot hoặc .ttf lên trước mà không lường trước hậu quả trên các trình duyệt di động hiện đại.

So sánh cú pháp khai báo src sai và đúng trong @font-face
Quy tắc vàng: Luôn đặt định dạng có tỷ lệ nén cao nhất (WOFF2) lên đầu tiên trong chuỗi khai báo font.

Sửa một dấu phẩy và trật tự ba định dạng

Cách khắc phục không đòi hỏi phải cài thêm plugin hay viết lại mã nguồn phức tạp. Nó chỉ yêu cầu hiểu đúng quy tắc nạp tài nguyên và sắp xếp lại thứ tự khai báo theo tiêu chuẩn vàng:

@font-face {
  font-family: 'FontAwesome';
  src: url('../fonts/fa4-subset.woff2?v=4.7.0') format('woff2'),
       url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),
       url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

Ngay sau khi đổi format('woff2') lên vị trí đầu tiên, trình duyệt Chrome và Safari lập tức nhận dạng bản nén WOFF2 siêu nhỏ, tải đúng 13.728 byte và hoàn tất việc dựng icon chỉ trong 18ms.

Những bẫy vô hình của cache và preload khi đổi font

Khi bạn thay đổi thứ tự khai báo font trong CSS, hãy chú ý đến hai bẫy kỹ thuật rất dễ làm phát sinh lỗi mới:

  • Đồng bộ thẻ Preload trong HTML: Nếu trong thẻ <head> của trang web bạn có khai báo <link rel="preload" as="font" type="font/woff2" ...>, URL trong thẻ preload phải trùng khớp từng ký tự (bao gồm cả query string ?v=...) với URL đứng đầu tiên trong file CSS. Nếu lệch nhau, trình duyệt sẽ tải cả hai file font cùng lúc.
  • Xóa sạch cache nén trang: Các plugin tăng tốc như FlyingPress thường lưu trữ bản HTML và CSS đã minify trên đĩa cứng. Phải purge cache toàn diện để đảm bảo khách truy cập nhận được stylesheet có thứ tự nạp mới.

Tương tự như việc tôi từng cắt bỏ 82% file icon mà không icon nào thành ô vuông hay bài học bốn lần đoán sai nguồn gây nhảy giao diện CLS: một chi tiết kỹ thuật nhỏ như thứ tự một dòng khai báo có thể quyết định toàn bộ thành bại của một chiến dịch tối ưu hóa tốc độ trang web.

Có thể bạn thích

Để lại bình luận