Menggunakan tipografi lanjutan dengan font lokal

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

Font yang aman untuk web

Jika Anda telah melakukan pengembangan web cukup lama, Anda mungkin ingat apa yang disebut font yang aman untuk web. {i>Font<i} ini diketahui tersedia di hampir semua {i>instance<i} pada sistem operasi yang paling sering digunakan (yaitu Windows, macOS, distribusi Linux yang paling umum, Android, dan iOS). Pada awal 2000-an, Microsoft bahkan memelopori inisiatif yang disebut font inti TrueType untuk Web yang menyediakan font ini secara gratis dengan tujuan yang "setiap kali Anda mengunjungi situs Web yang menetapkannya, Anda akan melihat laman persis dengan yang ditujukan oleh desainer situs". Ya, ini termasuk situs yang disetel di Comic Sans MS. Berikut adalah tumpukan font klasik yang aman untuk web (dengan penggantian akhir dari sans-serif ) mungkin terlihat seperti ini:

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

Font web

Hari-hari di mana {i>font<i} yang aman untuk web menjadi sangat penting sudah lama berlalu. Hari ini, tersedia font web, beberapa di antaranya adalah bahkan font variabel yang dapat kita ubah lebih lanjut dengan mengubah nilai untuk berbagai sumbu yang terbuka. Anda dapat menggunakan {i>font<i} 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 ini, Anda kemudian dapat menggunakan {i>font<i} web khusus dengan menentukan font-family, seperti biasa:

body {
  font-family: 'FlamboyantSansSerif';
}

Font lokal sebagai vektor sidik jari

Kebanyakan {i>font<i} web berasal dari web. Namun, fakta yang menarik adalah Properti src di @font-face deklarasi, selain url() , juga menerima local() . Hal ini memungkinkan font kustom dimuat (secara tiba-tiba) secara lokal. Jika pengguna memiliki FlamboyantSansSerif yang diinstal di sistem operasi mereka, salinan lokal akan digunakan, bukan yang sedang diunduh:

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

Pendekatan ini memberikan mekanisme fallback yang bagus yang berpotensi menghemat bandwidth. Di Internet, sayangnya, kita tidak bisa memiliki hal-hal baik. Masalah dengan fungsi local() adalah disalahgunakan untuk pelacakan sidik jari browser. Ternyata, daftar {i>font<i} yang telah diinstal oleh pengguna bisa identitas. Banyak perusahaan memiliki {i>font<i} perusahaan mereka sendiri yang dipasang pada laptop. Misalnya, Google memiliki font perusahaan yang disebut Google Sans.

Aplikasi Font Book macOS 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 dikenal, seperti Google Sans. Penyerang akan mencoba merender teks menetapkan font ini pada kanvas dan mengukur glyph. Jika glyph sesuai dengan bentuk elemen {i>font<i} perusahaan, penyerang telah mendapatkan serangan. Jika glyph tidak cocok, penyerang tahu bahwa {i>font<i} pengganti {i>default<i} digunakan karena {i>font<i} perusahaan tidak diinstal. Untuk detail selengkapnya tentang serangan ini dan serangan sidik jari browser lainnya, baca makalah survei oleh Laperdix dk.

Font perusahaan terpisah, bahkan hanya daftar font yang terinstal dapat mengidentifikasi. Situasi dengan vektor serangan ini telah menjadi begitu buruk sehingga baru-baru ini tim WebKit memutuskan menjadi "hanya sertakan [dalam daftar font yang tersedia] font dan font web yang disertakan dengan sistem, tetapi bukan font yang diinstal pengguna secara lokal". (Inilah artikel tentang cara memberikan akses ke font lokal.)

Local Font Access API

Bagian awal artikel ini mungkin membuat Anda dalam suasana hati negatif. Dapatkah kita benar-benar tidak memiliki banyak hal? Jangan khawatir. Kita pikir kita bisa, dan mungkin tidak ada harapan. Tapi sebelumnya, saya akan menjawab pertanyaan yang mungkin Anda tanyakan pada diri sendiri.

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

Alat desain dan grafis berkualitas profesional secara historis sulit untuk diberikan web. Salah satu hambatan adalah ketidakmampuan untuk mengakses dan menggunakan beragam keterampilan yang dibuat dan diberi petunjuk yang telah diinstal secara lokal oleh desainer. Dengan font web, publikasi mungkin dilakukan kasus penggunaan, tetapi gagal mengaktifkan akses terprogram ke bentuk glyph vektor dan tabel font yang digunakan oleh rasterizer untuk merender garis batas glyph. Demikian juga tidak ada cara untuk mengakses biner {i>font<i} web layanan otomatis dan data skalabel.

  • Alat desain membutuhkan akses ke byte font untuk melakukan implementasi tata letak OpenType mereka sendiri dan memungkinkan alat desain untuk memikat pada tingkat yang lebih rendah, untuk tindakan seperti melakukan filter vektor atau bertransformasi pada bentuk glyph.
  • Developer mungkin memiliki stack font lama untuk aplikasi yang mereka bawa ke web. Untuk menggunakan tumpukan ini, mereka biasanya memerlukan akses langsung ke data {i>font<i}, sesuatu yang tidak sediakan.
  • Beberapa font mungkin tidak dilisensikan untuk dikirim melalui web. Misalnya, Linotype memiliki lisensi untuk beberapa font yang hanya mencakup penggunaan di desktop.

Local Font Access API merupakan upaya untuk memecahkan masalah ini. Ini terdiri dari dua bagian:

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

Dukungan browser

Dukungan Browser

  • Chrome: 103.
  • Edge: 103.
  • Firefox: tidak didukung.
  • Safari: tidak didukung.

Sumber

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
}

Menghitung font lokal

Untuk mendapatkan daftar font yang diinstal secara lokal, Anda perlu memanggil window.queryLocalFonts(). Tujuan pertama kali, hal ini akan memicu dialog izin, yang dapat disetujui atau ditolak oleh pengguna. Jika pengguna menyetujui {i>font<i} lokal yang akan dikueri, browser akan mengembalikan larik dengan data {i>font<i} yang dapat Anda ulangi. Setiap font direpresentasikan sebagai objek FontData dengan properti family (misalnya, "Comic Sans MS"), fullName (misalnya, "Comic Sans MS"), postscriptName (untuk 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 Anda hanya tertarik pada sebagian font, Anda juga dapat memfilternya berdasarkan 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() Objek FontData. SFNT adalah format file {i>font<i} yang dapat berisi {i>font<i} lain, seperti PostScript, Font 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 Local Font Access API beraksi di demo di bawah. Pastikan juga untuk memeriksa kode sumber. Demo menampilkan elemen kustom bernama <font-select> yang mengimplementasikan pemilih font lokal.

Pertimbangan privasi

Izin "local-fonts" tampaknya memberikan platform yang sangat mudah digunakan dengan sidik jari. Namun, browser bebas untuk mengembalikan apa pun yang mereka inginkan. Misalnya, {i>browser<i} yang berfokus pada anonimitas dapat memilih hanya menyediakan serangkaian {i>font<i} {i>default<i} yang terpasang pada browser. Demikian pula, browser tidak diperlukan untuk memberikan data tabel persis seperti yang muncul di {i>disk<i}.

Jika memungkinkan, Local Font Access API dirancang untuk hanya mengekspos informasi yang diperlukan untuk memungkinkan kasus penggunaan yang disebutkan. API Sistem dapat menghasilkan daftar font terinstal yang tidak ada dalam acak atau dengan urutan yang diurutkan, tetapi dalam urutan instalasi {i>font<i}. Mengembalikan dengan tepat daftar font terinstal yang diberikan oleh API sistem semacam itu dapat mengekspos data tambahan yang dapat digunakan untuk pelacakan sidik jari, dan kasus penggunaan yang ingin kita aktifkan tidak dibantu dengan mempertahankan pengurutan ini. Sebagai seorang , API ini mengharuskan data yang ditampilkan diurutkan sebelum ditampilkan.

Keamanan dan izin

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

Kontrol pengguna

Akses ke font pengguna sepenuhnya di bawah kendali mereka dan tidak akan diizinkan kecuali jika "local-fonts", seperti yang tercantum dalam registry izin, diberikan.

Transparansi

Apakah situs telah diberi akses ke {i>font<i} lokal pengguna akan terlihat di lembar informasi situs.

Persistensi izin

Izin "local-fonts" akan dipertahankan di antara pemuatan ulang halaman. Lisensi dapat dicabut melalui site information.

Masukan

Tim Chrome ingin mengetahui pengalaman Anda saat menggunakan Local Font Access API.

Beri tahu kami tentang desain API

Apakah ada sesuatu terkait API yang tidak berfungsi seperti yang Anda harapkan? Atau apakah ada metode yang hilang yang dibutuhkan untuk menerapkan ide Anda? Memiliki pertanyaan atau komentar tentang keamanan model? Ajukan masalah spesifikasi di repo GitHub yang sesuai, atau tambahkan pendapat Anda ke masalah yang ada.

Laporkan masalah terkait penerapan

Apakah Anda menemukan bug pada implementasi Chrome? Atau apakah implementasinya berbeda dengan spesifikasi? Laporkan bug di new.crbug.com. Pastikan untuk menyertakan detail sebanyak mungkin, instruksi sederhana untuk mereproduksi, dan masukkan Blink>Storage>FontAccess dalam kotak Components. Glitch sangat cocok untuk membagikan repro dengan cepat dan mudah.

Menunjukkan dukungan untuk API

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

Kirim tweet ke @ChromiumDev menggunakan hashtag #LocalFontAccess dan biarkan kami tahu 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 telah ditinjau oleh Joe Medley, Dominik Röttsches, dan Olivier Yiptong. Banner besar oleh Brett Jordan di Buka pembuka.