שימוש בטיפוגרפיה מתקדמת עם גופנים מקומיים

ללמוד איך Local Font Access API מאפשר לגשת לגופנים שהותקנו באופן מקומי אצל המשתמש ולקבל עליהם פרטים ברמה נמוכה

גופנים בטוחים באינטרנט

אם אתם מפתחים אתרים מספיק זמן, ייתכן שתזכרו את מה שנקרא גופנים בטוחים באינטרנט. ידוע שהגופנים האלה זמינים כמעט בכל המופעים של מערכות ההפעלה הנפוצות ביותר (כלומר Windows, macOS, ההפצות הנפוצות ביותר של Linux, Android ו-iOS). בתחילת שנות ה-2000, Microsoft אפילו הובילה יוזמה בשם גופני ליבה מסוג TrueType לאינטרנט, שסיפקה את הגופנים להורדה בחינם עם המטרה ש"בכל פעם שתבקרו באתר שבו הם מופיעים, תראו דפים בדיוק כמו שמעצב האתר התכוון אליו". כן, זה כולל אתרים שהוגדרו ב-Comic Sans MS. הנה מקבץ גופנים קלאסי בטוח באינטרנט (עם החלופה האולטימטיבית לגופן sans-serif) שעשוי להיראות כך:

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

גופני אינטרנט

חלפו הימים שבהם הגופנים בטוחים באינטרנט היו חשובים מאוד. היום יש לנו גופני אינטרנט, חלקם אפילו גופנים משתנים שאפשר לשנות את הערכים שלהם על ידי שינוי הערכים של הצירים החשופים השונים. אפשר להשתמש בגופני אינטרנט על ידי הצהרה על בלוק @font-face בתחילת ה-CSS, שמציין את קובצי הגופנים להורדה:

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

לאחר מכן אפשר להשתמש בגופן האינטרנט המותאם אישית על ידי ציון font-family כרגיל:

body {
  font-family: 'FlamboyantSansSerif';
}

גופנים מקומיים כווקטור של טביעת אצבע

רוב גופני האינטרנט מגיעים מהאינטרנט. עם זאת, עובדה מעניינת היא שהמאפיין src בהצהרה @font-face, מלבד הפונקציה url(), מקבל גם הוא פונקציה local(). זה מאפשר לטעון גופנים מותאמים אישית (הפתעה!) באופן מקומי. אם מערכת ההפעלה של המשתמש FlamboyantSansSerif מותקנת אצל המשתמש, העותק המקומי ישמש ולא תתבצע הורדה שלו:

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

הגישה הזו מספקת מנגנון חלופי נחמד שיכול לחסוך ברוחב פס. לצערנו, באינטרנט לא יכולים להיות לנו דברים נחמדים. הבעיה בפונקציה local() היא שאפשר לנצל אותה לרעה לצורך יצירה של טביעת אצבע דיגיטלית (fingerprinting) של הדפדפן. מתברר שרשימת הגופנים שהמשתמש התקין יכולה להיות זיהוי למדי. לחברות רבות יש גופנים עסקיים משלהן שמותקנים במחשבים ניידים של העובדים. לדוגמה, ל-Google יש גופן ארגוני בשם Google Sans.

אפליקציית Font Book של macOS, שבה רואים תצוגה מקדימה של הגופן Google Sans.
הגופן Google Sans שמותקן במחשב נייד של עובד Google.

תוקף עלול לנסות לזהות באיזו חברה מישהו עובד, על ידי בדיקת קיומו של מספר גדול של גופנים ארגוניים ידועים, כמו Google Sans. התוקף ינסה לעבד את הטקסט שמוגדר בגופנים האלה על קנבס ולמדוד את הגליפים. אם הגליפים תואמים לצורה המוכרת של הגופן הארגוני, לתוקפים יש פגיעה. אם הגליפים לא תואמים, התוקף יודע שנעשה שימוש בגופן חלופי שמוגדר כברירת מחדל כי לא הותקן הגופן הארגוני. לקבלת פרטים מלאים על התקפות האלה והתקפות אחרות של טביעת אצבע דיגיטלית (fingerprinting) בדפדפן, קראו את מאמר הסקר של Laperdix et al.

הגופנים של החברה שונים זה מזה, וניתן לזהות רק את רשימת הגופנים המותקנים. המצב עם וקטור ההתקפה הזה הפך להיות כל כך גרוע, שלאחרונה צוות WebKit החליט "לכלול רק [ברשימת הגופנים הזמינים] גופני אינטרנט וגופני אינטרנט שמגיעים עם מערכת ההפעלה, אך לא גופנים שהותקנו באופן מקומי על ידי המשתמש". (וכאן אני מציג מאמר על הענקת גישה לגופנים מקומיים).

ממשק API של גישה לגופנים מקומיים

יכול להיות שתחילת המאמר הזה גרמה לך למצב רוח שלילי. אנחנו באמת לא יכולים לספק דברים נחמדים? אל דאגה. אנחנו חושבים שאנחנו יכולים, ואולי הכול לא חסר תקווה. אבל קודם כול, אני רוצה לענות על שאלה שאתם שואלים את עצמכם.

למה אנחנו צריכים את Local Font Access API כשקיימים גופני אינטרנט?

בעבר היה קשה לפרסם באינטרנט כלי עיצוב וגרפיקה באיכות מקצועית. אחד מאבני הבניין גרם לחוסר היכולת לגשת למגוון המלא של גופנים, שנבנו עם רמיזות באופן מקצועי, שמעצבים התקינו באופן מקומי. גופני אינטרנט מאפשרים תרחישים לדוגמה לפרסום, אבל לא מאפשרים גישה פרוגרמטית לצורות גליפים וקטוריים ולטבלאות גופנים שבהן משתמשים לרסטר כדי לעבד את קווי המתאר של הגליפים. כמו כן אין דרך לגשת לנתונים הבינאריים של גופן אינטרנט.

  • לכלי העיצוב נדרשת גישה לבייטים של גופנים כדי לבצע הטמעה משלהם של פריסת OpenType ולאפשר לכלי עיצוב להתחבר לרמות נמוכות יותר, לפעולות כמו ביצוע מסננים וקטוריים או ביצוע טרנספורמציות על צורות הגליף.
  • למפתחים עשויים להיות מקבצים של גופנים מדור קודם עבור היישומים שלהם שהם מביאים לאינטרנט. כדי להשתמש במקבצים האלה, בדרך כלל נדרשת גישה ישירה לנתוני הגופנים, משהו שגופני האינטרנט לא מספקים.
  • ייתכן שחלק מהגופנים לא יקבלו רישיון להעברה באינטרנט. לדוגמה, לגופנים מסוימים יש רישיון ל-Linotype שכולל רק שימוש במחשב.

Local Font Access API נועד לנסות לפתור את האתגרים האלה. הוא מורכב משני חלקים:

  • API לספירת גופנים, שמאפשר למשתמשים להעניק גישה לכל הגופנים הזמינים של המערכת.
  • מכל תוצאת ספירה, היכולת לבקש גישה לקונטיינר ב-SFNT ברמה נמוכה (מכווני בייטים) שכוללת את נתוני הגופנים המלאים.

תמיכת דפדפן

תמיכה בדפדפן

  • 103
  • 103
  • x
  • x

מקור

איך משתמשים ב-Local Font Access API

זיהוי תכונות

כדי לבדוק אם Local Font Access API נתמך, משתמשים בפקודה:

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

ספירת גופנים מקומיים

כדי לקבל רשימה של הגופנים שהותקנו באופן מקומי, צריך לקרוא ל-window.queryLocalFonts(). בפעם הראשונה, תוצג בקשה להרשאה שאותה המשתמש יכול לאשר או לדחות. אם המשתמש יאשר את הגופנים המקומיים שלו לשליחת שאילתות, הדפדפן יחזיר מערך עם נתוני גופנים שתוכלו להשתמש בהם בלולאה. כל גופן מיוצג כאובייקט FontData עם המאפיינים family (לדוגמה, "Comic Sans MS"), fullName (לדוגמה "Comic Sans MS"), postscriptName (לדוגמה, "ComicSansMS") ו-style (לדוגמה, "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);
}

אם אתם מעוניינים רק בקבוצת משנה של גופנים, תוכלו גם לסנן אותם לפי השמות של PostScript על ידי הוספת הפרמטר postscriptNames.

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

גישה לנתוני SFNT

גישה מלאה ל-SFNT זמינה דרך השיטה blob() של האובייקט FontData. SFNT הוא פורמט של קובץ גופנים שיכול להכיל גופנים אחרים כמו PostScript, TrueType, OpenType, Web Open Font Format (WOFF) ועוד.

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

הדגמה (דמו)

תוכלו לראות את ה-Local Font Access API בפעולה בהדגמה שלמטה. חשוב לבדוק גם את קוד המקור. בהדגמה מוצג רכיב מותאם אישית בשם <font-select> שמטמיע בורר גופנים מקומי.

שיקולי פרטיות

נראה שההרשאה "local-fonts" מספקת משטח עם יכולת טביעת אצבע גבוהה. עם זאת, דפדפנים יכולים להחזיר כל דבר שירצה. לדוגמה, דפדפנים שמתמקדים באנונימיות יבחרו רק קבוצה של גופני ברירת מחדל שמובנים בדפדפן. באופן דומה, דפדפנים לא נדרשים לספק נתוני טבלה בדיוק כפי שהם מופיעים בדיסק.

כשזה אפשרי, ה-Local Font Access API נועד לחשוף רק את המידע שצריך כדי להפעיל את התרחישים לדוגמה שצוינו. ממשקי ה-API של המערכת עשויים ליצור רשימה של גופנים מותקנים שלא בסדר אקראי או בסדר ממוין, אלא לפי סדר התקנת הגופנים. החזרה של הרשימה המדויקת של הגופנים שהותקנו על ידי ה-API של המערכת הזו יכולה לחשוף נתונים נוספים שאפשר להשתמש בהם ליצירה של טביעת אצבע דיגיטלית, ותרחישים לדוגמה שאנחנו רוצים להפעיל לא מקבלים עזרה בשמירה על הסדר הזה. לכן, ה-API הזה מחייב מיון של הנתונים המוחזרים לפני שיוחזרו.

אבטחה והרשאות

צוות Chrome תכנן והטמיע את ה-Local Font Access API באמצעות עקרונות הליבה שמוגדרים ב-Controlling Access to Power Platform features (שליטה בגישה לתכונות מתקדמות של פלטפורמת האינטרנט), כולל בקרת משתמשים, שקיפות וארגונומיה.

בקרת משתמשים

הגישה לגופנים של המשתמש נמצאת בשליטתו המלאה, והיא לא תורשה אלא אם תוענק ההרשאה "local-fonts", כפי שמפורט במרשם ההרשאות.

שקיפות

בגיליון המידע של האתר תוכלו לראות אם הוענקה לאתר גישה לגופנים המקומיים של המשתמש.

שמירת הרשאה

ההרשאה "local-fonts" תישמר בין טעינות מחדש של דפים. אפשר לבטל אותו בדף פרטי האתר.

משוב

צוות Chrome רוצה לשמוע על החוויה שלך עם Local Font Access API.

לספר לנו על עיצוב ה-API

האם יש משהו ב-API שלא פועל כצפוי? או האם חסרים שיטות או מאפיינים שאתם צריכים ליישם את הרעיון? יש לכם שאלה או הערה לגבי מודל האבטחה? שלחו בעיה במפרט במאגר GitHub המתאים, או הוסיפו את דעתכם לבעיה קיימת.

דיווח על בעיה בהטמעה

האם מצאת באג בהטמעה של Chrome? או שההטמעה שונה מהמפרט? דווחו על באג בכתובת new.crbug.com. הקפידו לכלול כמה שיותר פרטים, הוראות פשוטות לשחזור, והזינו Blink>Storage>FontAccess בתיבה רכיבים. גליץ' הוא כלי מעולה לשיתוף גיבויים מהירים וקלים.

הבעת תמיכה ב-API

האם ברצונך להשתמש ב-Local Font Access API? התמיכה הציבורית שלכם עוזרת לצוות של Chrome לתעדף תכונות, ומראה לספקי דפדפנים אחרים עד כמה חשוב לתמוך בהן.

שלח ציוץ אל @ChromiumDev באמצעות ה-hashtag #LocalFontAccess וספר לנו איפה אתם משתמשים בו ואיך אתם משתמשים בו.

אישורים

המפרט של Local Font Access API נערך על ידי Emil A. אקלונד, אלכס ראסל, ג'ושוע בל ואוליביה יפטונג. המאמר הזה נכתב על ידי Joe Medley, Dominik Röttsches ו-Olivier Yiptong. תמונה ראשית (Hero) של Brett Jordan ב-UnFlood.