Nội dung
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.ttfvới định dạngformat('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áchsrc. - 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.

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.

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.



