Sử dụng kiểu chữ nâng cao với phông chữ trên máy

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ó sẵn 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í đã khởi xướng một sáng kiến có tên là Phông chữ cốt lõi TrueType cho Web, nhằm cung cấp các phông chữ này cho người dùng tải xuống miễn phí với mục tiêu là "bất cứ khi nào bạn truy cập vào một trang web xác định, bạn sẽ thấy các trang chính xác như ý định của nhà thiết kế trang web". 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ể có dạng như sau:

body {
  font-family: Helvetica, Arial, sans-serif;
}

Phông chữ 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 các trục hiển thị. Bạn có thể sử dụng phông chữ trên web bằng cách khai báo khối @font-face ở đầu CSS để 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 số

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.

Ứng dụng Font Book (Sách phông chữ) của macOS hiển thị bản xem trước phông chữ Google Sans.
Phông chữ Google Sans được cài đặt trên máy tính xách tay của một nhân viên Google.

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 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 hiển thị 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 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ẽ bị một lượt truy cậ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 chưa đượ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 của bài viết này có thể đã khiến bạn có tâm trạng tiêu cực. Chúng ta thực sự không có những điều tốt đẹp sao? Đừng lo. Chúng tôi nghĩ rằng mình có thể và có lẽ mọi thứ không phải là 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 hỗ trợ 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à bộ tạo điểm ảnh sử dụng để hiển thị đườ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 quyền truy cập vào các byte phông chữ để triển khai bố cục OpenType riêng và cho phép các công cụ thiết kế kết nối ở cấp thấp hơn, cho các hành động như thực hiện bộ lọc vectơ hoặc biến đổi trên 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ùng chứa SFNT cấp thấp (theo hướng byte) bao gồm dữ liệu phông chữ đầy đủ.

Hỗ trợ trình duyệt

Hỗ trợ trình duyệt

  • Chrome: 103.
  • Edge: 103.
  • Firefox: không được hỗ trợ.
  • Safari: không được hỗ trợ.

Nguồn

Cách sử dụng Local Font Access API (API Truy cập phông chữ cục bộ)

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 đủ 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 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 ở mức độ cao. Tuy nhiên, trình duyệt có thể trả về bất kỳ nội dung nào họ 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ư trên đĩa.

Bất cứ khi nào có thể, API Truy cập phông chữ cục bộ chỉ đượ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ậ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 Local Font Access API theo các nguyên tắc cốt lõi được xác định trong 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 người dùng, tính minh bạch và 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 sổ đăng 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.

Khả năng lưu trữ cố định quyền

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ộ.

Cho chúng tôi biết 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.

Hiện thông tin hỗ trợ về API này

Bạn có dự định sử dụng API Truy cập phông chữ cục bộ không? Sự hỗ trợ 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 được 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.

Xác nhậ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 BellOlivier Yiptong. Bài viết này đã được Joe Medley, Dominik RöttschesOlivier Yiptong xem xét. Hình ảnh chính của Brett Jordan trên Unsplash.