olragon

Google Fonts cắt đôi font thì chữ Việt mất gì?

🌱 mầmgieo #css#font#tieng-viet#bai-hoc

Viết cho Ai làm web có chữ Việt và tự host hay cắt nhỏ web font, đang cân từng KB.

Sáng nay mình đọc một nhật ký sửa lỗi về font, gật đầu tới gần cuối, rồi khựng lại ở đúng một ví dụ. Ví dụ đó sai, mà cả bản sửa lại dựa vào nó.

Mấy con số đo lại mình đo ngày 4/11 trên máy Mac, bằng WebKit (lõi của Safari) và Chrome, hai bên ra y hệt nhau. Số KB từng trang lấy từ nhật ký. Phần đo có AI làm cùng.

English: What does Vietnamese lose when Google Fonts cuts a font in two?.

Vì sao chữ Việt nằm ở hai file

Mảnh vườn này chẳng tải web font nào, nhưng có một trang danh bạ nhỏ mình đang làm thì có, và font của nó lấy từ Google Fonts. Google chẳng gửi cả font. Nó cắt theo unicode-range: một file latin, một file vietnamese. Trình duyệt tải file nào có chữ cần vẽ, nên trang tiếng Việt gần như luôn tải cả hai.

Chỗ cắt chẳng nằm giữa chữ Việt và chữ Anh, mà nằm ngay giữa tiếng Việt. Các chữ á à ã â é è ê í ì ó ò õ ô ú ù ý có sẵn trong bảng Latin-1 nên ở file latin. Còn ă đ ĩ ũ ơ ư và mọi chữ có dấu chồng hay dấu nặng như ạ ả ấ ệ ộ ự thì ở file vietnamese. Trong các bài trên mảnh vườn này, 16,4% chữ cái nằm ở file vietnamese, và 32,7% cặp chữ đứng cạnh nhau bước qua ranh giới đó.

Kerning là khoảng dịch riêng cho từng cặp chữ, như kéo o sát vào dưới cánh chữ T. Bảng kerning nằm trong file font, nên một cặp chỉ có tác dụng khi cả hai chữ cùng một file. Tới đây nhật ký nói đúng.

Nhật ký bỏ kerning vì lý do gì

Trang đó đang gọt font: 12 file, 87,2 KB. Nhật ký thấy kerning chiếm khoảng một phần tư, rồi bỏ nó đi với hai lý do. Một: cặp quan trọng nhất là cá nằm ở hai file, nên kerning chưa từng chạy ở chỗ cần. Hai: chụp màn hình trước và sau chẳng khác gì, chữ lớn nhất trang chẳng nhúc nhích.

Lý do một sai ngay từ bảng mã: á là U+00E1, thuộc file latin, cùng file với c. Mình đo thêm thì cặp đó cũng chẳng có kerning nào, ở cả hai font trang đó dùng.

Lý do hai nghe chắc hơn, nhưng mình đo ba cặp chữ trong dòng chữ lớn đó và cả ba đều bằng 0, trên cả hai font. Nó đứng yên vì chẳng có gì để dịch. Phép thử đó chỉ nhìn đúng chỗ không thể nhúc nhích, rồi kết luận cho cả trang.

Đo lại thì còn bao nhiêu

Phản xạ của mình là tìm xem bảng kerning có bao nhiêu cặp. Nhưng cặp có trong bảng chưa chắc xuất hiện trong bài, nên mình đo thẳng trên trình duyệt. Lấy mọi cặp chữ trong các bài mình viết thật, đo bề rộng lúc font-kerning: normal và lúc none, ở hai cách nạp: hai file như Google gửi, và một file gộp xin bằng tham số text=. Cặp nào chênh ít nhất nửa phần nghìn em thì tính là có kerning.

font, bàilần gặp cặp có kerningcòn lại khi tách hai filemất
Newsreader, bài tiếng Việt5.2383.87026%
Be Vietnam Pro, bài tiếng Việt8.3664.87742%
Newsreader, bài tiếng Anh8.4838.4660,2%
Be Vietnam Pro, bài tiếng Anh12.00811.9680,3%

Vậy là "chưa từng chạy" sai: hơn nửa số kerning trong bài tiếng Việt vẫn chạy bình thường. Nhưng phần mất cũng thật. Số cặp mất đúng bằng số cặp có kerning mà bước qua hai file, chẳng dư chẳng thiếu một lần nào, nên nguyên nhân thì nhật ký đoán trúng.

Cái mất đi lại rơi vào những chữ gặp hoài. Ở Newsreader, ấy, ạy, về, vớ đều mất khoảng 31 phần nghìn em. Ở Be Vietnam Pro, đi mất 40 và đó mất 20 phần nghìn, mà đây là kerning đẩy ra cho chữ đ khỏi đụng chữ sau. Một font vẽ kỹ cho tiếng Việt, tới lúc về máy người đọc thì phần kỹ đó rớt lại giữa hai file.

Bạn thử bấm dưới đây. Mấy chữ này vẽ bằng font hệ thống trên máy bạn, gọn trong một file, nên chẳng cặp nào bị cắt, và con số là độ dịch thật ở cỡ chữ này.

  • To
  • AV
  • Và
  • Vậy
  • về
  • với
  • đi
  • đó

Vậy bỏ kerning có sai không

Mình nghĩ là không sai, và đây là chỗ mình đổi ý giữa chừng. Quyết định vẫn đúng, chỉ là lý do phải khác: đổi vài px lấy 21,7 KB. Bỏ riêng kerning trên 12 file cũ thì từ 87.196 còn 65.480 byte, tức 24,9%. Nhật ký từng ghi 25,3 KB, nhưng số đó lấy từ hai bản dựng khác bộ nén nên chẳng lặp lại nổi.

Đổi lại mất gì? Ở cỡ chữ 16 px, 31 phần nghìn em là nửa px. Cộng hết độ dịch trên một dòng 70 chữ cái tiếng Việt thì cỡ 2 tới 4 px. Chữ thường trong bài khó ai thấy. Nhưng To dịch 106 phần nghìn, ở tiêu đề 48 px là 5 px, và phần này trước đó chạy thật, bây giờ mất thật, nhất là ở trang tiếng Anh.

Lý do cũng quan trọng vì người sau sẽ dựa vào nó. Ai đọc "kerning chưa từng chạy" sẽ yên tâm bỏ ở mọi chỗ, kể cả tiêu đề tiếng Anh. Ai đọc "đổi vài px lấy 21,7 KB" thì còn cân lại được khi trang đó đã nhẹ rồi. Mình gửi mấy số này về cho trang đó, và trong ngày nhật ký đã sửa cả lý do lẫn con số, còn quyết định giữ nguyên.

Có đường thứ ba là gộp một file, giữ đủ mọi cặp. Nhật ký đo file gộp gần bằng hai file cộng lại, lệch chừng 100 byte. Mình làm lại với 182 ký tự của trang thì khác: Newsreader 20,4 KB so với 17,2 KB, Be Vietnam Pro 12,1 KB so với 10,8 KB. Vậy gộp tốn thêm chừng 12 tới 19%, chứ chẳng miễn phí. Với logo hay tiêu đề cố định thì text= vẫn là cách gọn, vì chỉ cần vài chữ.

Trang bạn đang ra sao

Dán đoạn này vào console trên trang bạn, sửa danh sách cặp cho hợp với chữ bạn hay dùng. Số in ra là độ dịch tính theo phần nghìn em. Nếu có font tách hai file mà ấy ra 0 còn To khác 0, bạn đang gặp đúng chuyện này.

const s = document.createElement("span");
s.style.cssText = "position:absolute;white-space:pre;font-size:1000px;font-variant-ligatures:none";
document.body.append(s);
const w = (k, t) => { s.style.fontKerning = k; s.textContent = t; return s.getBoundingClientRect().width; };
for (const p of ["To", "Va", "ấy", "về", "vớ", "đi", "đó"]) console.log(p, w("normal", p) - w("none", p));
s.remove();

Chưa biết gì

  • Mắt người đọc có thấy khác không thì mình chưa thử với ai. Mình chỉ có số px, mà số px chẳng phải là cảm giác đọc.
  • Mình chưa giải thích nổi vì sao nhật ký từng ghi file gộp 17,1 KB, còn mình làm lại thì ra 20,4 KB. Mình đoán bản đó thiếu kerning, nhưng bỏ kerning thì file gộp còn 10,8 KB, nên chẳng phải. Nhật ký giờ dùng số của mình, nên hai bên khớp nhau cũng chẳng chứng minh thêm gì.
  • Mẫu đo là bài mình tự viết, văn một người, chỉ cỡ 51 nghìn chữ cái. Tỷ lệ có thể khác với văn bản khác.
  • Mình chỉ đo hai font, ở nét thường. Font khác có bảng kerning dày hay mỏng hơn thì số sẽ khác hẳn, nên bạn cứ đo font của bạn.

Bạn từng bỏ một thứ vì lý do sai, mà kết quả vẫn đúng chưa? Viết cho mình một lá thư bên dưới nha.

Gửi Ba rồng một lá thư

Đọc xong muốn nói gì thì viết cho mình nha. Thư chỉ tới tay mình, chẳng tự hiện lên trang. Lá nào hay mà bạn cho phép, mình chép lại dưới bài, không kèm tên bạn.

Mảnh vườn giữ gì từ lá thư này

Từ terminal cũng gửi được: curl -d 'msg=…' olragon.com/garden/kern-split-vi/letter