Menggunakan tipografi lanjutan dengan font lokal

Pelajari cara Local Font Access API memungkinkan Anda mengakses font yang diinstal secara lokal oleh pengguna dan mendapatkan detail tingkat rendah tentang font tersebut

Font aman web

Jika sudah cukup lama melakukan pengembangan web, Anda mungkin ingat apa yang disebut sebagai font aman web. Font ini diketahui tersedia di hampir semua instance sistem operasi yang paling banyak digunakan (yaitu Windows, macOS, distribusi Linux yang paling umum, Android, dan iOS). Pada awal tahun 2000-an, Microsoft bahkan memelopori inisiatif bernama TrueType core fonts for the Web yang menyediakan font ini untuk didownload secara gratis dengan tujuan "setiap kali Anda mengunjungi situs yang menentukannya, Anda akan melihat halaman persis seperti yang diinginkan desainer situs". Ya, ini termasuk situs yang disetel dalam Comic Sans MS. Berikut adalah stack font aman web klasik (dengan penggantian terakhir font sans-serif apa pun) mungkin terlihat seperti ini:

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

Font web

Hari-hari ketika font web-safe benar-benar penting sudah lama berlalu. Saat ini, kita memiliki font web, beberapa di antaranya bahkan merupakan font variabel yang dapat kita sesuaikan lebih lanjut dengan mengubah nilai untuk berbagai sumbu yang ditampilkan. Anda dapat menggunakan font web dengan mendeklarasikan blok @font-face di awal CSS, yang menentukan file font yang akan didownload:

@font-face {
  font-family: 'FlamboyantSansSerif';
  src: url('flamboyant.woff2');
}

Setelah itu, Anda dapat menggunakan font web kustom dengan menentukan font-family, seperti biasa:

body {
  font-family: 'FlamboyantSansSerif';
}

Font lokal sebagai vektor sidik jari

Sebagian besar font web berasal dari, ya, web. Namun, fakta menariknya adalah properti src dalam deklarasi @font-face, selain fungsi url(), juga menerima fungsi local(). Hal ini memungkinkan font kustom dimuat (tentu saja!) secara lokal. Jika pengguna kebetulan telah menginstal FlamboyantSansSerif di sistem operasinya, salinan lokal akan digunakan, bukan didownload:

@font-face {
  font-family: 'FlamboyantSansSerif';
  src: local('FlamboyantSansSerif'), url('flamboyant.woff2');
}

Pendekatan ini menyediakan mekanisme penggantian yang baik yang berpotensi menghemat bandwidth. Di Internet, sayangnya, kita tidak bisa mendapatkan hal-hal yang baik. Masalah pada fungsi local() adalah bahwa fungsi ini dapat disalahgunakan untuk sidik jari browser. Ternyata, daftar font yang telah diinstal pengguna dapat mengidentifikasi pengguna tersebut. Banyak perusahaan memiliki font perusahaan sendiri yang diinstal di laptop karyawan. Misalnya, Google memiliki font perusahaan yang disebut Google Sans.

Aplikasi Font Book macOS yang menampilkan pratinjau font Google Sans.
Font Google Sans yang diinstal di laptop karyawan Google.

Penyerang dapat mencoba menentukan perusahaan tempat seseorang bekerja dengan menguji keberadaan sejumlah besar font perusahaan yang diketahui seperti Google Sans. Penyerang akan mencoba merender set teks dalam font ini di kanvas dan mengukur glyph. Jika glif cocok dengan bentuk font perusahaan yang diketahui, penyerang berhasil. Jika glif tidak cocok, penyerang mengetahui bahwa font pengganti default digunakan karena font perusahaan tidak diinstal. Untuk mengetahui detail selengkapnya tentang serangan sidik jari browser ini dan serangan lainnya, baca makalah survei oleh Laperdix et al.

Selain font perusahaan, bahkan hanya daftar font yang diinstal dapat mengidentifikasi. Situasi dengan vektor serangan ini telah menjadi sangat buruk sehingga baru-baru ini tim WebKit memutuskan untuk "hanya menyertakan font web dan font yang disertakan dengan sistem operasi [dalam daftar font yang tersedia], tetapi tidak menyertakan font yang diinstal pengguna secara lokal". (Dan di sini saya, dengan artikel tentang memberikan akses ke font lokal.)

Local Font Access API

Awal artikel ini mungkin membuat Anda merasa negatif. Apakah kita benar-benar tidak bisa memiliki hal-hal yang bagus? Jangan khawatir. Kami yakin kami bisa, dan mungkin semuanya tidak sia-sia. Namun, izinkan kami menjawab pertanyaan yang mungkin Anda ajukan.

Mengapa kita memerlukan Local Font Access API saat ada font web?

Alat desain dan grafik berkualitas profesional secara historis sulit disediakan di web. Salah satu kendalanya adalah ketidakmampuan untuk mengakses dan menggunakan berbagai font yang dibuat dan di-hint secara profesional yang telah diinstal secara lokal oleh desainer. Font web memungkinkan beberapa kasus penggunaan publikasi, tetapi gagal mengaktifkan akses terprogram ke bentuk glyph vektor dan tabel font yang digunakan oleh rasterizer untuk merender garis luar glyph. Demikian pula, tidak ada cara untuk mengakses data biner font web.

  • Alat desain memerlukan akses ke byte font untuk melakukan implementasi tata letak OpenType sendiri dan memungkinkan alat desain terhubung di tingkat yang lebih rendah, untuk tindakan seperti melakukan filter atau transformasi vektor pada bentuk glyph.
  • Developer mungkin memiliki stack font lama untuk aplikasi yang mereka bawa ke web. Untuk menggunakan stack ini, biasanya diperlukan akses langsung ke data font, yang tidak disediakan oleh font web.
  • Beberapa font mungkin tidak memiliki lisensi untuk ditayangkan di web. Misalnya, Linotype memiliki lisensi untuk beberapa font yang hanya mencakup penggunaan desktop.

Local Font Access API adalah upaya untuk mengatasi tantangan ini. Terdiri dari dua bagian:

  • API enumerasi font, yang memungkinkan pengguna memberikan akses ke kumpulan lengkap font sistem yang tersedia.
  • Dari setiap hasil enumerasi, kemampuan untuk meminta akses penampung SFNT tingkat rendah (berorientasi byte) yang mencakup data font lengkap.

Dukungan browser

Browser Support

  • Chrome: 103.
  • Edge: 103.
  • Firefox: not supported.
  • Safari: not supported.

Source

Cara menggunakan Local Font Access API

Deteksi fitur

Untuk memeriksa apakah Local Font Access API didukung, gunakan:

if ('queryLocalFonts' in window) {
  // The Local Font Access API is supported
}

Mencantumkan font lokal

Untuk mendapatkan daftar font yang diinstal secara lokal, Anda harus memanggil window.queryLocalFonts(). Pertama kali, tindakan ini akan memicu dialog izin, yang dapat disetujui atau ditolak oleh pengguna. Jika pengguna menyetujui font lokal mereka dikueri, browser akan menampilkan array dengan data font yang dapat Anda iterasi. Setiap font ditampilkan sebagai objek FontData dengan properti family (misalnya, "Comic Sans MS"), fullName (misalnya, "Comic Sans MS"), postscriptName (misalnya, "ComicSansMS"), dan style (misalnya, "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);
}

Jika hanya tertarik dengan sebagian font, Anda juga dapat memfilternya berdasarkan nama PostScript dengan menambahkan parameter postscriptNames.

const availableFonts = await window.queryLocalFonts({
  postscriptNames: ['Verdana', 'Verdana-Bold', 'Verdana-Italic'],
});

Mengakses data SFNT

Akses SFNT penuh tersedia melalui metode blob() dari objek FontData. SFNT adalah format file font yang dapat berisi font lain, seperti font PostScript, TrueType, OpenType, Web Open Font Format (WOFF), dan lainnya.

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);
}

Demo

Anda dapat melihat cara kerja Local Font Access API dalam demo. Pastikan untuk melihat kode sumber juga. Demo ini menampilkan elemen kustom bernama <font-select> yang menerapkan pemilih font lokal.

Pertimbangan privasi

Izin "local-fonts" tampaknya menyediakan platform yang sangat mudah diidentifikasi. Namun, browser bebas menampilkan apa pun yang diinginkannya. Misalnya, browser yang berfokus pada anonimitas dapat memilih untuk hanya menyediakan sekumpulan font default yang ada di browser. Demikian pula, browser tidak diwajibkan untuk memberikan data tabel persis seperti yang muncul di disk.

Jika memungkinkan, Local Font Access API dirancang untuk hanya mengekspos informasi yang diperlukan untuk mengaktifkan kasus penggunaan yang disebutkan. API sistem dapat menghasilkan daftar font yang diinstal tidak dalam urutan acak atau urutan yang diurutkan, tetapi dalam urutan penginstalan font. Menampilkan persis daftar font yang diinstal yang diberikan oleh API sistem tersebut dapat mengekspos data tambahan yang dapat digunakan untuk sidik jari, dan kasus penggunaan yang ingin kami aktifkan tidak dibantu dengan mempertahankan pengurutan ini. Akibatnya, API ini mengharuskan data yang ditampilkan diurutkan sebelum ditampilkan.

Keamanan dan izin

Tim Chrome telah mendesain dan menerapkan Local Font Access API menggunakan prinsip inti yang ditentukan dalam Mengontrol Akses ke Fitur Platform Web yang Canggih, termasuk kontrol pengguna, transparansi, dan ergonomi.

Kontrol pengguna

Akses ke font pengguna sepenuhnya berada di bawah kendali mereka dan tidak akan diizinkan kecuali izin "local-fonts", sebagaimana tercantum dalam pendaftaran izin, diberikan.

Transparansi

Apakah situs telah diberi akses ke font lokal pengguna akan terlihat di lembar informasi situs.

Persistensi izin

Izin "local-fonts" akan dipertahankan di antara pemuatan ulang halaman. Izin dapat dicabut melalui lembar informasi situs.

Masukan

Tim Chrome ingin mengetahui pengalaman Anda dengan Local Font Access API.

Beri tahu kami tentang desain API

Apakah ada sesuatu tentang API yang tidak berfungsi seperti yang Anda harapkan? Atau, apakah ada metode atau properti yang tidak ada dan perlu Anda terapkan untuk mewujudkan ide Anda? Ada pertanyaan atau komentar tentang model keamanan? Laporkan masalah spesifikasi di repo GitHub yang sesuai, atau tambahkan pendapat Anda ke masalah yang sudah ada.

Melaporkan masalah terkait penerapan

Apakah Anda menemukan bug pada penerapan Chrome? Atau apakah implementasinya berbeda dengan spesifikasi? Laporkan bug di new.crbug.com. Pastikan untuk menyertakan detail sebanyak mungkin, petunjuk sederhana untuk mereproduksi, dan masukkan Blink>Storage>FontAccess di kotak Komponen.

Menunjukkan dukungan untuk API

Apakah Anda berencana menggunakan Local Font Access API? Dukungan publik Anda membantu tim Chrome memprioritaskan fitur dan menunjukkan kepada vendor browser lain betapa pentingnya dukungan untuk fitur tersebut.

Kirim tweet ke @ChromiumDev menggunakan hashtag #LocalFontAccess dan beri tahu kami di mana dan bagaimana Anda menggunakannya.

Ucapan terima kasih

Spesifikasi Local Font Access API diedit oleh Emil A. Eklund, Alex Russell, Joshua Bell, dan Olivier Yiptong. Artikel ini ditinjau oleh Joe Medley, Dominik Röttsches, dan Olivier Yiptong. Gambar banner besar oleh Brett Jordan di Unsplash.