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

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

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

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

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. התוקף ינסה לעבד את הטקסט שמוגדרים בגופנים האלה על קנבס ומודדים את הגליפים. אם הגליפים תואמים לצורה הידועה של גופן ארגוני, התוקף פגע. אם הגליפים לא תואמים, התוקף יודע נעשה שימוש בגופן החלופי שמוגדר כברירת מחדל כי הגופן הארגוני לא הותקן. לפרטים מלאים על ומתקפות אחרות של טביעות אצבע דיגיטליות בדפדפן, סקר מאת Laperdix et al.

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

Local Font Access API

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

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

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

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

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

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

תמיכה בדפדפנים

תמיכה בדפדפן

  • Chrome: 103.
  • קצה: 103.
  • Firefox: לא נתמך.
  • Safari: לא נתמך.

מקור

איך משתמשים ב-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 מלאה זמינה באמצעות ה-method 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 בפעולה demo בהמשך. חשוב גם לעיין קוד מקור. ההדגמה מציגה רכיב מותאם אישית בשם <font-select> מפעילה בוחר גופנים מקומי.

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

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

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

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

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

שליטת משתמשים

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

שקיפות

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

שמירת ההרשאות

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

משוב

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

מתארים את עיצוב ה-API

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

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

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

הצגת תמיכה ב-API

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

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

אישורים

המפרט של Local Font Access API נערך על ידי אמיל א. אקלונד, אלכס ראסל, Joshua Bell, וגם אוליבייר יפטונג. המאמר הזה נבדק על ידי ג'ו מדלי, דומיניק רוטצ'ס, וגם אוליבייר יפטונג. תמונה ראשית (Hero) מאת Brett Jordan פועל ביטול הפתיחה.