איך ממשק ה-API לגישה לגופנים מקומיים מאפשר לכם לגשת לגופנים שהותקנו באופן מקומי במכשיר של המשתמש ולקבל פרטים ברמה נמוכה עליהם
גופנים בטוחים לאינטרנט
אם אתם מפתחי אתרים ותיקים, יכול להיות שאתם זוכרים את הגופנים המתאימים לאינטרנט.
הגופנים האלה זמינים כמעט בכל המופעים של מערכות ההפעלה הנפוצות ביותר (כלומר Windows, macOS, הפצות Linux הנפוצות ביותר, Android ו-iOS). בתחילת שנות ה-2000, Microsoft אפילו הובילה יוזמה שנקראת TrueType core fonts for the Web, שבמסגרתה הפונטים האלה היו זמינים להורדה בחינם. המטרה של היוזמה הזו הייתה "כאשר מבקרים באתר אינטרנט שמציין אותם, רואים את הדפים בדיוק כפי שמי שעיצב את האתר התכוון". כן, הנתונים האלה כללו אתרים שהוגדרו ב-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()
היא שאפשר לנצל אותה לרעה לצורך יצירה של טביעת אצבע של הדפדפן. מסתבר שאפשר לזהות משתמשים לפי רשימת הגופנים שהם התקינו. לרוב החברות יש גופנים עסקיים משלהם שמותקנים במחשבים הניידים של העובדים. לדוגמה, ל-Google יש גופן חברה שנקרא Google Sans.
תוקף יכול לנסות לקבוע באיזו חברה משתמש מסוים עובד על ידי בדיקה של נוכחות של מספר גדול של גופנים ארגוניים מוכרים, כמו Google Sans. התוקף ינסה לבצע רינדור של טקסט שהוגדר בגופנים האלה על קנבס ולמדוד את הגליפים. אם הגליפים תואמים לצורה המוכרת של הגופן הארגוני, התוקף מקבל הייט. אם הגופנים לא תואמים, התוקף יודע שנעשה שימוש בגופן חלופי שמוגדר כברירת מחדל כי הגופן העסקי לא הותקן. פרטים מלאים על ההתקפה הזו ועל התקפות אחרות של טביעת אצבע של דפדפן זמינים בסקירה של Laperdix et al.
מלבד גופנים של חברות, גם רשימת הגופנים המותקנים יכולה להיות מזהה. המצב של וקטור ההתקפה הזה החמיר כל כך עד שבזמן האחרון צוות WebKit החליט "לכלול [ברשימת הגופנים הזמינים] רק גופנים אינטרנטיים וגופנים שמגיעים עם מערכת ההפעלה, אבל לא גופנים שהמשתמשים התקינו באופן מקומי". (ואני כאן, עם מאמר בנושא מתן גישה לגופנים מקומיים).
Local Font Access API
יכול להיות שהחלק הראשון של המאמר גרם לכם להרגיש רע. האם באמת אי אפשר ליהנות מדברים נחמדים? אל דאגה. אנחנו חושבים שאנחנו יכולים, ואולי הכול לא אבוד. אבל קודם, אשמח לענות על שאלה שיכול להיות ששאלת את עצמך.
למה אנחנו צריכים את Local Font Access API כשיש גופני אינטרנט?
בעבר היה קשה להציע באינטרנט כלים לעיצוב ולגרפיקה באיכות מקצועית. אחת מהבעיות הייתה חוסר היכולת לגשת למגוון המלא של גופנים שנוצרו באופן מקצועי ועוברים תהליך של הוספת טיפים, שהמעצבים התקינו באופן מקומי, ולהשתמש בהם. גופני אינטרנט מאפשרים לבצע כמה תרחישים לדוגמה של פרסום, אבל הם לא מאפשרים גישה פרוגרמטית לצורות של הגליפים וקובצי הגופנים שמוגדרים כוקטור, שבהם משתמשים הרסטריזרים כדי ליצור את קווי המתאר של הגליפים. כמו כן, אין דרך לגשת לנתונים הבינאריים של גופן אינטרנט.
- לכלים לעיצוב צריכה להיות גישה לבייטים של הגופן כדי לבצע הטמעה משלהם של פריסה ב-OpenType, ולאפשר לכלים לעיצוב להתחבר ברמות נמוכות יותר, לפעולות כמו ביצוע מסננים וקונברטיבים של צורות הגליפים.
- יכול להיות שלמפתחים יש סטאקים קודמים של גופנים לאפליקציות שהם מעבירים לאינטרנט. כדי להשתמש בסטאקים האלה, בדרך כלל נדרשת גישה ישירה לנתוני הגופן, וגופני אינטרנט לא מספקים את זה.
- יכול להיות שחלק מהגופנים לא מורשים להעברה באינטרנט. לדוגמה, ל-Linotype יש רישיון לגופנים מסוימים שכולל רק שימוש במחשב.
Local Font Access API הוא ניסיון לפתור את האתגרים האלה. הוא מורכב משני חלקים:
- API למניין גופנים, שמאפשר למשתמשים להעניק גישה לקבוצה המלאה של גופנים זמינים במערכת.
- מכל תוצאה של ספירה, היכולת לבקש גישה לקונטיינר SFNT ברמה נמוכה (ממוקדת-בייט) שכוללת את נתוני הגופן המלאים.
תמיכה בדפדפנים
איך משתמשים ב-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 בהתאם לעקרונות המרכזיים שמוגדרים במאמר בקרת הגישה לתכונות עוצמתיות של פלטפורמת האינטרנט, כולל בקרת משתמשים, שקיפות וארגונומיה.
שליטת משתמשים
הגישה לגופנים של משתמש היא בשליטתו המלאה, והיא לא תתאפשר אלא אם תתקבל ההרשאה "local-fonts"
, כפי שמופיעה במרשם ההרשאות.
שקיפות
תוכלו לראות אם אתר קיבל גישה לגופנים המקומיים של המשתמש בגיליון המידע של האתר.
התמדת ההרשאות
ההרשאה "local-fonts"
תישמר בין טעינות מחדש של דפים. אפשר לבטל אותו באמצעות הגיליון פרטי האתר.
משוב
צוות Chrome רוצה לשמוע על החוויה שלכם עם Local Font Access API.
תיאור של עיצוב ה-API
האם יש משהו ב-API שלא פועל כמצופה? או אולי חסרות שיטות או מאפיינים שאתם צריכים כדי להטמיע את הרעיון? יש לכם שאלות או הערות לגבי מודל האבטחה? אתם יכולים לשלוח דיווח על בעיה במפרט במאגר GitHub המתאים, או להוסיף את המחשבות שלכם לבעיה קיימת.
דיווח על בעיה בהטמעה
מצאתם באג בהטמעה של Chrome? או שההטמעה שונה מהמפרט?
שולחים דיווח על באג בכתובת new.crbug.com. חשוב לכלול כמה שיותר פרטים, הוראות פשוטות לשחזור הבעיה ולהזין את הערך Blink>Storage>FontAccess
בתיבה Components.
Glitch הוא כלי מצוין לשיתוף שחזור מהיר וקל של באגים.
תמיכה ב-API
האם אתם מתכננים להשתמש ב-Local Font Access API? התמיכה הציבורית שלכם עוזרת לצוות Chrome לתת עדיפות לתכונות, ומראה לספקי דפדפנים אחרים כמה חשובה התמיכה בהן.
אפשר לשלוח ציוץ אל @ChromiumDev עם ההאשטאג #LocalFontAccess
ולספר לנו איפה ואיך אתם משתמשים בו.
קישורים שימושיים
- הסבר
- טיוטת מפרט
- באג ב-Chromium לגבי ספירת גופנים
- באג ב-Chromium לגישה לטבלת הגופנים
- הרשומה ב-ChromeStatus
- מאגר GitHub
- בדיקת התג
- עמדת Mozilla בנושא תקנים
תודות
Emil A. Eklund, Alex Russell, Joshua Bell ו-Olivier Yiptong. הבדיקה של המאמר בוצעה על ידי Joe Medley, Dominik Röttsches ו-Olivier Yiptong. התמונה הראשית (Hero) של Brett Jordan ב-Unsplash.