Bỏ qua tới nội dung
Performance· ·8 phút đọc

WOFF2 và cách giảm dung lượng font web (subset tiếng Việt)

Nguyen Hien
WOFF2 và cách giảm dung lượng font web (subset tiếng Việt)
Cỡ chữ

Mỗi file font tải về là một phần của ngân sách tốc độ trang. Một font Google phổ biến ở dạng TTF gốc có thể nặng 150-200 KB cho mỗi kiểu (regular, bold, italic…), và một trang dùng 3-4 kiểu dễ cõng cả mega-byte font trước khi chữ kịp hiện. Chọn đúng định dạng và cắt đúng bộ ký tự là hai đòn bẩy gọn nhất để hạ con số đó. Bài này nói về định dạng file font và dung lượng — khác với chuyện font lưu ở đâu hay hiện thế nào.

WOFF2 là gì và vì sao nó nhỏ nhất

WOFF2 không phải một kiểu chữ mới, mà là một lớp bọc nén (compression wrapper — vỏ nén) quanh bảng dữ liệu của font TTF/OTF, được thiết kế riêng cho việc truyền qua mạng. Điểm khác biệt nằm ở thuật toán nén: WOFF cũ dùng zlib, còn WOFF2 dùng Brotli — cho dung lượng nhỏ hơn WOFF khoảng 30% theo tài liệu của web.dev.

So sánh thực tế với một kiểu chữ thông dụng (Roboto Regular) cho thấy chênh lệch rõ:

Định dạngDung lượng (ví dụ)So với TTF
TTF (gốc, không nén)~168 KB100%
WOFF (zlib)~85 KBnhỏ hơn ~50%
WOFF2 (Brotli)~53 KBnhỏ hơn ~68%

Con số cụ thể đổi theo từng font, nhưng thứ tự luôn giữ nguyên: WOFF2 < WOFF < TTF/OTF. File càng nhẹ thì chữ tải web về càng nhanh, góp phần kéo LCP (Largest Contentful Paint — thời điểm phần tử lớn nhất hiện ra) xuống dưới ngưỡng tốt 2,5 giây.

Sơ đồ vì sao năm 2026 chỉ cần định dạng font WOFF2 và có thể bỏ woff, ttf, eot
WOFF2 nén tốt nhất và được hỗ trợ rộng nên các định dạng cũ đã thành dư thừa.

Vì sao 2026 chỉ cần WOFF2 (bỏ woff, ttf, eot)

Vài năm trước, cách làm an toàn là khai báo nhiều định dạng dự phòng trong @font-face: eot cho IE cũ, ttf cho trình duyệt cổ, woff cho lớp giữa, woff2 cho trình duyệt mới. Năm 2026, chuỗi dự phòng đó gần như thừa.

WOFF2 đã đạt hỗ trợ trên 97% trình duyệt đang dùng — toàn bộ Chrome, Edge, Firefox, Safari các bản còn được cập nhật. Những trình duyệt không hiểu WOFF2 (như IE11) hầu hết đã ngừng vòng đời. Việc nhồi thêm ttf/eot chỉ làm phình thư mục font và rối khai báo CSS, đổi lại một nhóm khách gần như không tồn tại. Khai báo gọn cho 2026:

@font-face{ 
  font-family: "Inter";
  src: url("/fonts/inter-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
 }

Nếu bạn thật sự cần phục vụ một nhóm trình duyệt rất cũ, mới thêm một dòng woff dự phòng phía sau. Còn lại, một định dạng WOFF2 là đủ. Chuyện đặt font-display ra sao để tránh chữ vô hình thuộc về cách hiển thị — xem riêng bài font-display swap.

Subset: cắt bộ ký tự để giảm thêm 70-90%

Đổi sang WOFF2 mới giải quyết phần nén. Đòn bẩy lớn thứ hai là subsetting (cắt tập con — chỉ giữ những ký tự bạn thực dùng). Một file font đầy đủ có thể chứa hàng nghìn glyph: Latin, Cyrillic, Hy Lạp, dấu toán học, ký hiệu… Trang tiếng Việt gần như không bao giờ chạm tới phần lớn số đó.

Theo web.dev, cắt font xuống đúng bộ ký tự cần dùng có thể giảm 70-90% dung lượng mà mắt thường không thấy khác biệt. Với tiếng Việt, bộ ký tự cần giữ gồm:

  • Basic Latin (U+0000-00FF) — chữ cái a-z, A-Z, số, dấu câu cơ bản.
  • Latin Extended-A và Extended-B — phần chứa nhiều ký tự có dấu.
  • Latin Extended Additional (U+1E00-1EFF) — đây là vùng chứa các nguyên âm mang dấu thanh tiếng Việt (ầ, ế, ợ, ữ…). Thiếu vùng này, chữ tiếng Việt sẽ vỡ dấu.

Công cụ chuẩn để làm việc này là pyftsubset trong thư viện fontTools (web.dev khuyến nghị). Một lệnh mẫu cắt font xuống Latin + tiếng Việt rồi xuất thẳng ra WOFF2:

pyftsubset Inter-Regular.ttf 
  --unicodes="U+0000-00FF,U+0100-024F,U+1E00-1EFF,U+2000-206F" 
  --flavor=woff2 
  --output-file=inter-regular.woff2

Sau bước này, một font 60-70 KB (đã WOFF2) thường rớt về 25-35 KB cho riêng phần tiếng Việt + Latin. Web22 áp đúng cách này khi tự lưu Google Font cho web22.dev: tải bản gốc về, cắt theo bộ ký tự tiếng Việt, xuất WOFF2 rồi đặt cạnh máy chủ thay vì gọi sang Google.

Subset file khác với unicode-range

Hai khái niệm hay bị nhầm. Subset là cắt thật dung lượng file font. Còn unicode-range trong CSS chỉ báo cho trình duyệt biết “file này chứa khoảng ký tự nào” để nó chỉ tải file khi trang có ký tự thuộc khoảng đó — bản thân nó không làm file nhỏ đi. Cách đúng là làm cả hai: cắt file vật lý bằng pyftsubset, rồi khai báo unicode-range để trình duyệt chỉ tải đúng subset cần. Đây cũng chính là cơ chế Google Fonts dùng khi chia một font thành nhiều file con theo ngôn ngữ.

Sơ đồ quy trình subset font cắt bộ ký tự tiếng Việt và Latin để giảm dung lượng font cho một trang
Cắt bớt ký tự không dùng và xuất WOFF2 giúp font nhẹ đi đáng kể.

Quy trình tối ưu font gọn cho một trang

  1. Liệt kê đúng số kiểu chữ trang thật sự dùng (thường 2-3 weight là đủ; bỏ italic nếu không xài).
  2. Tải file gốc TTF/OTF của từng kiểu.
  3. Subset theo bộ ký tự tiếng Việt + Latin bằng pyftsubset, xuất --flavor=woff2.
  4. Khai báo @font-face chỉ với WOFF2, kèm font-display: swap.
  5. Tự lưu font cạnh máy chủ thay vì gọi tên miền ngoài, để bớt một lượt kết nối DNS/TLS.

Bước cuối — lưu font ở đâu và vì sao tự lưu nhanh hơn gọi sang Google — thuộc về chủ đề self-host, xem riêng bài self-host Google Font.

Câu hỏi thường gặp

WOFF2 có làm chữ xấu hơn TTF không?

Không. WOFF2 chỉ là cách nén lại đúng dữ liệu glyph của TTF/OTF; khi trình duyệt giải nén, hình chữ giống hệt bản gốc. Subset cũng không đổi nét chữ, chỉ bỏ những ký tự bạn không dùng.

Subset rồi mà trang hiện ký tự đặc biệt thì sao?

Trình duyệt sẽ rơi về font hệ thống cho ký tự thiếu. Vì vậy hãy giữ đủ vùng Latin Extended Additional cho tiếng Việt và thêm khoảng dấu câu (U+2000-206F) để tránh lỗi dấu nháy, gạch ngang dài.

Có cần variable font không?

Nếu trang dùng nhiều weight của cùng một họ chữ, một file variable font WOFF2 đôi khi nhẹ hơn tổng nhiều file rời. Nhưng nếu chỉ dùng 1-2 weight thì các file tĩnh đã subset thường gọn hơn.

Đọc tiếp

Bài viết
cùng chủ đề.

Tất cả bài viết