Tìm hiểu cách API Truy cập phông chữ cục bộ cho phép bạn truy cập vào phông chữ đã cài đặt cục bộ của người dùng và nhận thông tin chi tiết cấp thấp về các phông chữ đó
Phông chữ an toàn cho web
Nếu đã làm việc trong lĩnh vực phát triển web đủ lâu, bạn có thể nhớ đến phông chữ an toàn cho web.
Các phông chữ này được biết là có trên gần như tất cả các phiên bản của các hệ điều hành được sử dụng nhiều nhất (cụ thể là Windows, macOS, các bản phân phối Linux phổ biến nhất, Android và iOS). Vào đầu những năm 2000, Microsoft thậm chí còn đi đầu trong một sáng kiến có tên là phông chữ cốt lõi TrueType cho Web. Sáng kiến này cung cấp các phông chữ này để tải xuống miễn phí với mục tiêu "bất cứ khi nào bạn truy cập vào một trang web chỉ định các phông chữ này, bạn sẽ thấy các trang giống như nhà thiết kế trang web dự định". Có, bao gồm cả các trang web được đặt bằng phông chữ Comic Sans MS. Dưới đây là một ngăn xếp phông chữ an toàn cho web cổ điển (với phông chữ dự phòng cuối cùng là bất kỳ phông chữ sans-serif
nào) có thể trông như sau:
body {
font-family: Helvetica, Arial, sans-serif;
}
Phông chữ trên web
Thời kỳ phông chữ an toàn cho web thực sự quan trọng đã qua lâu rồi. Ngày nay, chúng ta có phông chữ web, một số phông chữ thậm chí còn là phông chữ biến mà chúng ta có thể điều chỉnh thêm bằng cách thay đổi giá trị cho nhiều trục hiển thị. Bạn có thể sử dụng phông chữ web bằng cách khai báo khối @font-face
ở đầu CSS. Khối này chỉ định(các) tệp phông chữ cần tải xuống:
@font-face {
font-family: 'FlamboyantSansSerif';
src: url('flamboyant.woff2');
}
Sau đó, bạn có thể sử dụng phông chữ web tuỳ chỉnh bằng cách chỉ định font-family
như bình thường:
body {
font-family: 'FlamboyantSansSerif';
}
Phông chữ trên máy dưới dạng vectơ vân tay
Hầu hết phông chữ trên web đều đến từ web. Tuy nhiên, một thực tế thú vị là thuộc tính src
trong phần khai báo @font-face
, ngoài hàm url()
, cũng chấp nhận hàm local()
. Điều này cho phép tải phông chữ tuỳ chỉnh trên máy (thật bất ngờ!). Nếu người dùng tình cờ đã cài đặt FlamboyantSansSerif trên hệ điều hành của họ, thì bản sao cục bộ sẽ được sử dụng thay vì tải xuống:
@font-face {
font-family: 'FlamboyantSansSerif';
src: local('FlamboyantSansSerif'), url('flamboyant.woff2');
}
Phương pháp này cung cấp một cơ chế dự phòng hiệu quả có thể giúp tiết kiệm băng thông. Rất tiếc, trên Internet, chúng ta không thể có những điều tốt đẹp. Vấn đề với hàm local()
là hàm này có thể bị lợi dụng để tạo vân tay trình duyệt. Hóa ra, danh sách phông chữ mà người dùng đã cài đặt có thể khá dễ nhận dạng. Nhiều công ty có phông chữ riêng được cài đặt trên máy tính xách tay của nhân viên. Ví dụ: Google có phông chữ công ty tên là Google Sans.
Kẻ tấn công có thể cố gắng xác định công ty mà một người làm việc bằng cách kiểm tra xem có một số lượng lớn phông chữ doanh nghiệp đã biết như Google Sans hay không. Kẻ tấn công sẽ cố gắng kết xuất văn bản được đặt trong các phông chữ này trên một canvas và đo lường các ký tự. Nếu các ký tự khớp với hình dạng đã biết của phông chữ công ty, thì kẻ tấn công sẽ có một kết quả trùng khớp. Nếu các ký tự không khớp, kẻ tấn công sẽ biết rằng phông chữ thay thế mặc định đã được sử dụng vì phông chữ của công ty không được cài đặt. Để biết toàn bộ thông tin chi tiết về cuộc tấn công này và các cuộc tấn công tạo vân tay trình duyệt khác, hãy đọc bài khảo sát của Laperdix và cộng sự.
Ngoài phông chữ của công ty, ngay cả danh sách phông chữ đã cài đặt cũng có thể được xác định. Tình huống với phương thức tấn công này đã trở nên tồi tệ đến mức gần đây, nhóm WebKit quyết định "chỉ đưa vào [danh sách phông chữ có sẵn] phông chữ web và phông chữ đi kèm với hệ điều hành, nhưng không bao gồm phông chữ do người dùng cài đặt cục bộ". (Và tôi đang viết một bài viết về cách cấp quyền truy cập vào phông chữ trên máy.)
API Truy cập phông chữ cục bộ
Phần đầu bài viết này có thể khiến bạn cảm thấy không vui. Chúng ta thực sự không thể có những điều tốt đẹp sao? Đừng lo. Chúng tôi nghĩ rằng chúng ta có thể và có thể không phải mọi thứ đều vô vọng. Nhưng trước tiên, hãy để tôi trả lời một câu hỏi mà có thể bạn đang tự hỏi.
Tại sao chúng ta cần API Quyền truy cập phông chữ trên máy khi có phông chữ web?
Trước đây, các công cụ đồ hoạ và thiết kế chất lượng chuyên nghiệp rất khó phân phối trên web. Một trở ngại là không thể truy cập và sử dụng đầy đủ các phông chữ được tạo và gợi ý chuyên nghiệp mà nhà thiết kế đã cài đặt cục bộ. Phông chữ web hỗ trợ một số trường hợp sử dụng phát hành, nhưng không bật quyền truy cập có lập trình vào các hình dạng ký tự vectơ và bảng phông chữ mà trình tạo điểm ảnh sử dụng để kết xuất đường viền ký tự. Tương tự, không có cách nào để truy cập vào dữ liệu nhị phân của phông chữ web.
- Các công cụ thiết kế cần có quyền truy cập vào các byte phông chữ để triển khai bố cục OpenType của riêng mình và cho phép các công cụ thiết kế kết nối ở các cấp thấp hơn, đối với các thao tác như thực hiện bộ lọc vectơ hoặc chuyển đổi trên các hình dạng ký tự.
- Nhà phát triển có thể có các ngăn xếp phông chữ cũ cho các ứng dụng mà họ đang đưa lên web. Để sử dụng các ngăn xếp này, bạn thường phải có quyền truy cập trực tiếp vào dữ liệu phông chữ, một tính năng mà phông chữ web không cung cấp.
- Một số phông chữ có thể không được cấp phép để phân phối qua web. Ví dụ: Linotype có giấy phép cho một số phông chữ chỉ bao gồm quyền sử dụng trên máy tính.
API Quyền truy cập phông chữ trên máy là một nỗ lực nhằm giải quyết những thách thức này. Phương thức này bao gồm hai phần:
- API liệt kê phông chữ cho phép người dùng cấp quyền truy cập vào toàn bộ phông chữ hệ thống có sẵn.
- Từ mỗi kết quả liệt kê, khả năng yêu cầu quyền truy cập vào vùng chứa SFNT cấp thấp (theo hướng byte) bao gồm toàn bộ dữ liệu phông chữ.
Hỗ trợ trình duyệt
Cách sử dụng API Quyền truy cập phông chữ trên máy
Phát hiện tính năng
Để kiểm tra xem API Quyền truy cập phông chữ cục bộ có được hỗ trợ hay không, hãy sử dụng:
if ('queryLocalFonts' in window) {
// The Local Font Access API is supported
}
Liệt kê phông chữ trên máy
Để có được danh sách phông chữ đã cài đặt cục bộ, bạn cần gọi window.queryLocalFonts()
. Lần đầu tiên, thao tác này sẽ kích hoạt lời nhắc cấp quyền mà người dùng có thể phê duyệt hoặc từ chối. Nếu người dùng phê duyệt việc truy vấn phông chữ cục bộ, trình duyệt sẽ trả về một mảng chứa dữ liệu phông chữ mà bạn có thể lặp lại. Mỗi phông chữ được biểu thị dưới dạng một đối tượng FontData
có các thuộc tính family
(ví dụ: "Comic Sans MS"
), fullName
(ví dụ: "Comic Sans MS"
), postscriptName
(ví dụ: "ComicSansMS"
) và style
(ví dụ: "Regular"
).
// Query for all available fonts and log metadata.
try {
const availableFonts = await window.queryLocalFonts();
for (const fontData of availableFonts) {
console.log(fontData.postscriptName);
console.log(fontData.fullName);
console.log(fontData.family);
console.log(fontData.style);
}
} catch (err) {
console.error(err.name, err.message);
}
Nếu chỉ quan tâm đến một số phông chữ, bạn cũng có thể lọc các phông chữ đó dựa trên tên PostScript bằng cách thêm tham số postscriptNames
.
const availableFonts = await window.queryLocalFonts({
postscriptNames: ['Verdana', 'Verdana-Bold', 'Verdana-Italic'],
});
Truy cập dữ liệu SFNT
Bạn có thể truy cập đầy đủ vào SFNT thông qua phương thức blob()
của đối tượng FontData
. SFNT là một định dạng tệp phông chữ có thể chứa các phông chữ khác, chẳng hạn như phông chữ PostScript, TrueType, OpenType, Web Open Font Format (WOFF) và các phông chữ khác.
try {
const availableFonts = await window.queryLocalFonts({
postscriptNames: ['ComicSansMS'],
});
for (const fontData of availableFonts) {
// `blob()` returns a Blob containing valid and complete
// SFNT-wrapped font data.
const sfnt = await fontData.blob();
// Slice out only the bytes we need: the first 4 bytes are the SFNT
// version info.
// Spec: https://docs.microsoft.com/en-us/typography/opentype/spec/otff#organization-of-an-opentype-font
const sfntVersion = await sfnt.slice(0, 4).text();
let outlineFormat = 'UNKNOWN';
switch (sfntVersion) {
case '\x00\x01\x00\x00':
case 'true':
case 'typ1':
outlineFormat = 'truetype';
break;
case 'OTTO':
outlineFormat = 'cff';
break;
}
console.log('Outline format:', outlineFormat);
}
} catch (err) {
console.error(err.name, err.message);
}
Bản minh hoạ
Bạn có thể xem cách hoạt động của API Truy cập phông chữ cục bộ trong màn hình minh hoạ bên dưới. Hãy nhớ xem cả mã nguồn. Bản minh hoạ này giới thiệu một phần tử tuỳ chỉnh có tên là <font-select>
triển khai bộ chọn phông chữ cục bộ.
Những điều cần cân nhắc về quyền riêng tư
Quyền "local-fonts"
có vẻ như cung cấp một bề mặt có thể nhận dạng vân tay cao. Tuy nhiên, trình duyệt có thể trả về bất kỳ nội dung nào mà trình duyệt muốn. Ví dụ: các trình duyệt tập trung vào tính năng ẩn danh có thể chọn chỉ cung cấp một bộ phông chữ mặc định được tích hợp sẵn trong trình duyệt. Tương tự, trình duyệt không bắt buộc phải cung cấp dữ liệu bảng chính xác như xuất hiện trên đĩa.
Bất cứ khi nào có thể, API Truy cập phông chữ cục bộ được thiết kế để chỉ hiển thị chính xác thông tin cần thiết để hỗ trợ các trường hợp sử dụng được đề cập. API hệ thống có thể tạo danh sách phông chữ đã cài đặt không theo thứ tự ngẫu nhiên hoặc thứ tự sắp xếp, mà theo thứ tự cài đặt phông chữ. Việc trả về chính xác danh sách phông chữ đã cài đặt do API hệ thống như vậy cung cấp có thể hiển thị dữ liệu bổ sung có thể được dùng để tạo vân tay số, đồng thời các trường hợp sử dụng mà chúng ta muốn bật sẽ không được hỗ trợ bằng cách giữ nguyên thứ tự này. Do đó, API này yêu cầu dữ liệu được trả về phải được sắp xếp trước khi trả về.
Tính bảo mật và quyền truy cập
Nhóm Chrome đã thiết kế và triển khai API Truy cập phông chữ cục bộ bằng cách sử dụng các nguyên tắc cốt lõi được xác định trong bài viết Kiểm soát quyền truy cập vào các tính năng mạnh mẽ của nền tảng web, bao gồm cả quyền kiểm soát của người dùng, tính minh bạch và tính công thái học.
Quyền kiểm soát của người dùng
Người dùng có toàn quyền kiểm soát quyền truy cập vào phông chữ của họ và sẽ không được phép truy cập trừ khi quyền "local-fonts"
(như được liệt kê trong nhật ký quyền) được cấp.
Sự minh bạch
Bạn có thể xem liệu một trang web đã được cấp quyền truy cập vào phông chữ trên máy của người dùng hay chưa trong trang thông tin trang web.
Quyền ổn định
Quyền "local-fonts"
sẽ được duy trì giữa các lần tải lại trang. Bạn có thể thu hồi quyền này thông qua trang tính thông tin trang web.
Phản hồi
Nhóm Chrome muốn biết trải nghiệm của bạn với API Truy cập phông chữ cục bộ.
Giới thiệu cho chúng tôi về thiết kế API
API có hoạt động như mong đợi không? Hay có phương thức hoặc thuộc tính nào bị thiếu mà bạn cần để triển khai ý tưởng của mình không? Bạn có câu hỏi hoặc nhận xét về mô hình bảo mật không? Gửi vấn đề về thông số kỹ thuật trên kho lưu trữ GitHub tương ứng hoặc thêm ý kiến của bạn vào một vấn đề hiện có.
Báo cáo vấn đề về việc triển khai
Bạn có phát hiện lỗi khi triển khai Chrome không? Hay cách triển khai có khác với thông số kỹ thuật không?
Gửi lỗi tại new.crbug.com. Hãy nhớ cung cấp càng nhiều thông tin chi tiết càng tốt, hướng dẫn đơn giản để tái hiện lỗi và nhập Blink>Storage>FontAccess
vào hộp Components (Thành phần).
Glitch rất hữu ích để chia sẻ các bản tái hiện nhanh chóng và dễ dàng.
Hỗ trợ API
Bạn có dự định sử dụng API Truy cập phông chữ cục bộ không? Sự ủng hộ công khai của bạn giúp nhóm Chrome ưu tiên các tính năng và cho các nhà cung cấp trình duyệt khác thấy tầm quan trọng của việc hỗ trợ các tính năng đó.
Gửi một tweet đến @ChromiumDev bằng hashtag #LocalFontAccess
và cho chúng tôi biết bạn đang sử dụng ở đâu và như thế nào.
Đường liên kết hữu ích
- Giải thích
- Bản nháp thông số kỹ thuật
- Lỗi Chromium khi liệt kê phông chữ
- Lỗi Chromium khi truy cập vào bảng phông chữ
- Mục ChromeStatus
- Kho lưu trữ GitHub
- Xem xét thẻ
- Quan điểm của Mozilla về tiêu chuẩn
Lời cảm ơn
Thông số kỹ thuật của API Quyền truy cập phông chữ trên máy do Emil A. Eklund, Alex Russell, Joshua Bell và Olivier Yiptong. Bài viết này đã được Joe Medley, Dominik Röttsches và Olivier Yiptong xem xét. Hình ảnh chính của Brett Jordan trên Unsplash.