Nội dung
Mọi trang của marketing365.vn đều tải một file font tên là fontawesome-webfont.woff2, nặng 77.160 byte. Trong file đó có 675 icon. Trang thực tế dùng khoảng một trăm cái. Phần còn lại là icon Bitcoin, icon xe cứu thương, icon logo Foursquare — thứ mà site này sẽ không bao giờ vẽ ra.
Cắt bớt nghe rất dễ. Lý do gần như không ai làm là vì cái giá khi cắt hụt: thiếu đúng một icon thì chỗ đó hiện ra một ô vuông rỗng, và bạn thường không biết cho tới khi khách nhìn thấy. Bài này nói về cách bỏ 82% file đó mà đặt cái ô vuông ra ngoài vùng có thể xảy ra.

Vì sao cắt font icon lại đáng sợ hơn cắt CSS
Khi cắt file CSS của theme từ 1,2 MB xuống 243 KB, cắt hụt một luật thì hậu quả là một chỗ lệch màu hoặc lệch khoảng cách — khó chịu nhưng nhìn ra ngay và sửa được bằng cách thêm lại luật đó.
Font icon khác. Icon không phải hình, nó là ký tự. Mỗi icon nằm ở một điểm mã riêng, ví dụ mũi tên phải là U+F105, cái kính lúp là U+F002. Trình duyệt lấy ký tự đó ra khỏi file font. Nếu file font không chứa ký tự đó thì trình duyệt vẽ ô vuông thay thế, chứ nó không đi tìm file khác.
Và bạn không kiểm hết được. Site này có hơn 1.600 trang, một theme với hàng chục tuỳ chọn, plugin có thể chèn icon riêng, và bài viết tương lai có thể dùng bất kỳ icon nào. Danh sách “icon site đang dùng” là thứ thay đổi mỗi lần bạn bật một tuỳ chọn trong Customizer. Một cái subset dựng đúng hôm nay không có gì bảo đảm còn đúng sau ba tháng.
Khai báo hai @font-face cho cùng một họ chữ
Chỗ thoát nằm ở hai tính chất của CSS mà đứng riêng thì bình thường, ghép lại thì giải quyết đúng vấn đề trên.
Thứ nhất, một họ chữ được phép có nhiều khai báo @font-face, và với những ký tự mà nhiều khai báo cùng phủ, khai báo đứng sau thắng. Thứ hai, trình duyệt chỉ tải một file font khi trên trang thật sự có ký tự khớp vào nó — unicode-range là thứ nói cho nó biết khai báo này phủ những ký tự nào.
Theme đã khai báo họ FontAwesome trỏ vào file đầy đủ, không kèm unicode-range, nghĩa là khai báo đó phủ mọi ký tự. Việc cần làm là thêm một khai báo thứ hai, cùng tên họ, trỏ vào file subset, kèm danh sách chính xác những điểm mã mà subset có:
@font-face{
font-family:'FontAwesome';
src:url('/wp-content/themes/soledad-child/fonts/fa4-subset.woff2') format('woff2');
font-weight:normal; font-style:normal; font-display:swap;
unicode-range:U+F001,U+F003,U+F004,U+F005,U+F007,U+F00D,U+F013,...
}
Kết quả là hai nhánh trong sơ đồ ở trên. Icon nằm trong danh sách thì trình duyệt tải file 13.728 byte và không bao giờ hỏi tới file 77 KB. Icon nằm ngoài danh sách thì khai báo thứ hai không phủ nó, khai báo của theme phủ, nên trình duyệt tải file đầy đủ và vẽ icon đó bình thường.
Điểm quan trọng nằm ở chỗ này: cái giá của một subset thiếu sót không còn là ô vuông, mà là một lượt tải thêm trên đúng cái trang có icon lạ. Từ một lỗi hiển thị mà khách nhìn thấy, nó biến thành một khoản lãng phí băng thông mà không ai nhìn thấy. Nhờ vậy mới dám để cái subset nằm đó và quên đi.
Cái bẫy khi đi tìm danh sách icon đang dùng
Cách hiển nhiên để biết site dùng icon nào là quét file template tìm chuỗi fa-. Trên theme này cách đó cho ra danh sách sai.
Soledad có một hàm tên penci_icon_by_ver() trong inc/template-function.php. Class icon viết trong template là kiểu FontAwesome 5, ví dụ fab fa-facebook-f. Nhưng trước khi in ra HTML, hàm này đọc tuỳ chọn theme rồi viết lại class:
Đọc thêm: Content B2b Viết Thế Nào Cho Đúng Mục Tiêu?
$fontawesome_ver5 = get_theme_mod( 'penci_fontawesome_ver5' );
if ( ! $fontawesome_ver5 ) {
$class = str_replace( array( 'fab ', 'fal ', 'far ', 'fas ' ), 'fa ', $class );
if ( 'fa fa-facebook-f' == $class ) {
$class = str_replace( 'facebook-f', 'facebook', $class );
} elseif ( 'fa fa-thumbtack' == $class ) {
$class = str_replace( 'thumbtack', 'thumb-tack', $class );
}
...
Nghĩa là class trong mã nguồn và class ra tới trình duyệt là hai thứ khác nhau, và cái nào ra thì phụ thuộc vào một tuỳ chọn trong Customizer. Chưa kể một nhánh nữa: nếu bật icon dạng viền thì cả loạt icon mạng xã hội chuyển sang bộ penciicon- của theme, không dính gì tới FontAwesome.
Bài học rút ra không phải là “theme này viết dở”. Bài học là danh sách icon phải lấy từ HTML mà máy chủ thật sự in ra, không lấy từ mã nguồn template. Và ngay cả như vậy vẫn có thể sót, nên vẫn cần cái lưới an toàn ở phần trên.
Số đo sau khi lên production
Hai file cùng đang phục vụ trên tên miền thật, kiểm ngày 14/08/2026:
$ curl -sI .../soledad/fonts/fontawesome-webfont.woff2 → 200 77.160 B
$ curl -sI .../soledad-child/fonts/fa4-subset.woff2 → 200 13.728 B
Điểm mã trong file FontAwesome 4.7 đầy đủ 675
Điểm mã giữ lại trong subset 103 (−84,7%)
Kích thước −63.432 B (−82,2%)
Bài kiểm quan trọng hơn là nhánh phải của sơ đồ có bao giờ chạy không. Lấy HTML thật của 6 trang — trang chủ, hai trang chuyên mục, một bài viết, trang chủ đề, trang liên hệ — rồi đối chiếu mọi class fa- tìm được với bảng điểm mã của FontAwesome 4.7 và với danh sách unicode-range của subset. Kết quả: không trang nào có icon rơi ra ngoài subset. Nghĩa là trên những trang này, file 77 KB không được yêu cầu lần nào.
Nói cho đủ: 63.432 byte là con số của một lượt tải font, và font được trình duyệt lưu lại nên khách đọc trang thứ hai không tải lại. Chỗ nó có ý nghĩa là lượt vào đầu tiên, trên mạng di động — đúng chỗ mà tốc độ web trên điện thoại quyết định người ta ở lại hay thoát.
Đừng quên tải trước file subset
Có một chi tiết dễ bỏ sót và nó làm hỏng gần hết phần vừa tiết kiệm. File CSS tham chiếu tới font đang được nạp kiểu bất đồng bộ, nên trình duyệt không biết có cái font này cho tới khi CSS về và được áp dụng. Font vì thế bắt đầu tải rất muộn, và trong lúc chờ thì chỗ icon là khoảng trống.
Cách xử lý là khai báo tải trước ngay trong <head>:
<link rel="preload" as="font" type="font/woff2"
href=".../fa4-subset.woff2?v=1754024000" crossorigin>
Thuộc tính crossorigin là bắt buộc kể cả khi font nằm cùng tên miền — font luôn được tải ở chế độ nặc danh, thiếu thuộc tính này thì trình duyệt coi bản tải trước là một tài nguyên khác và tải lại lần nữa. Còn tham số ?v= lấy từ thời điểm sửa file, để lần sau dựng lại subset thì bản cũ trong bộ nhớ đệm tự hết hiệu lực.
Nếu bạn định làm việc này trên site của mình
- Lấy HTML đã render của khoảng năm đến mười trang đại diện, không đọc file template. Trích class icon, tra sang điểm mã bằng chính file CSS của bộ icon đang dùng.
- Dựng file subset từ danh sách điểm mã đó, và cho công cụ dựng ghi luôn danh sách ấy ra một file bên cạnh. Đọc
unicode-rangetừ file đó thay vì chép tay — chép tay là cách chắc chắn nhất để CSS lệch khỏi font sau lần dựng lại thứ hai. - Thêm khai báo
@font-facethứ hai sau khai báo của theme, đừng sửa hay xoá khai báo gốc. Khai báo gốc chính là lưới an toàn. - Tải trước file subset, nhớ
crossorigin. - Kiểm bằng cách mở tab Network rồi lướt vài trang: phải thấy file subset, không thấy file đầy đủ. Nếu thấy cả hai thì subset đang thiếu icon — không gấp, nhưng nên dựng lại.
Cả việc này gọn hơn nhiều so với cắt CSS, và không có phần đánh đổi khó chịu nào. Chỗ khó duy nhất là chấp nhận rằng bạn sẽ không bao giờ liệt kê đủ icon site mình dùng, rồi thiết kế sao cho việc liệt kê thiếu không còn quan trọng.



