از تایپوگرافی پیشرفته با فونت های محلی استفاده کنید

بیاموزید که چگونه Local Font Access API به شما امکان می دهد به فونت های نصب شده محلی کاربر دسترسی داشته باشید و جزئیات سطح پایینی در مورد آنها بدست آورید.

فونت های ایمن وب

اگر به اندازه کافی توسعه وب را انجام داده اید، ممکن است فونت های به اصطلاح امن وب را به خاطر بیاورید. این فونت‌ها تقریباً در تمام نمونه‌های پرکاربردترین سیستم‌عامل‌ها (یعنی Windows، macOS، رایج‌ترین توزیع‌های لینوکس، اندروید و iOS) در دسترس هستند. در اوایل دهه 2000، مایکروسافت حتی ابتکاری به نام فونت‌های اصلی 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() این است که می توان از آن برای انگشت نگاری مرورگر سوء استفاده کرد. به نظر می رسد، لیست فونت هایی که کاربر نصب کرده است می تواند بسیار قابل شناسایی باشد. بسیاری از شرکت ها فونت های شرکتی خود را دارند که روی لپ تاپ کارمندان نصب می شوند. به عنوان مثال، گوگل یک فونت شرکتی به نام Google Sans دارد.

برنامه macOS Font Book که پیش نمایشی از فونت Google Sans را نشان می دهد.
فونت Google Sans که روی لپ تاپ یکی از کارمندان گوگل نصب شده است.

یک مهاجم می تواند با آزمایش وجود تعداد زیادی فونت شرکتی شناخته شده مانند Google Sans ، تعیین کند که شخصی برای چه شرکتی کار می کند. مهاجم سعی می‌کند متنی را با این فونت‌ها بر روی بوم رندر کند و حروف را اندازه‌گیری کند. اگر حروف با شکل شناخته شده فونت شرکت مطابقت داشته باشد، مهاجم ضربه می خورد. اگر حروف‌ها مطابقت نداشته باشند، مهاجم می‌داند که از یک فونت جایگزین پیش‌فرض استفاده شده است زیرا فونت شرکتی نصب نشده است. برای جزئیات کامل در مورد این حمله و سایر حملات اثر انگشت مرورگر، مقاله نظرسنجی Laperdix و همکاران را بخوانید.

فونت های شرکت جدا از هم، حتی فقط لیست فونت های نصب شده را می توان شناسایی کرد. وضعیت این بردار حمله به قدری بد شده است که اخیراً تیم WebKit تصمیم گرفت "فقط فونت‌های وب و فونت‌هایی را که به همراه سیستم عامل ارائه می‌شوند [در لیست فونت‌های موجود] بگنجانند، اما فونت‌های نصب شده توسط کاربر محلی را شامل نمی‌شود" . (و اینجا هستم، با مقاله ای در مورد اعطای دسترسی به فونت های محلی.)

Local Font Access API

شروع این مقاله ممکن است شما را در روحیه منفی قرار داده باشد. آیا واقعاً می توانیم چیزهای خوبی نداشته باشیم؟ ناراحت نباش ما فکر می کنیم که می توانیم، و شاید همه چیز ناامید کننده نباشد . اما ابتدا اجازه دهید به سوالی که ممکن است از خودتان بپرسید پاسخ دهم.

چرا وقتی فونت های وب وجود دارد به Local Font Access API نیاز داریم؟

ارائه ابزارهای گرافیکی و طراحی با کیفیت حرفه ای در طول تاریخ دشوار بوده است. یکی از موانع، ناتوانی در دسترسی و استفاده از انواع فونت های حرفه ای ساخته شده و اشاره شده است که طراحان به صورت محلی نصب کرده اند. فونت‌های وب برخی موارد استفاده از انتشار را فعال می‌کنند، اما دسترسی برنامه‌ریزی شده به شکل‌های حروف برداری و جداول فونت‌های مورد استفاده توسط شطرنج‌سازها را برای ارائه خطوط کلی حروف فعال نمی‌کنند. به همین ترتیب هیچ راهی برای دسترسی به داده های باینری فونت وب وجود ندارد.

  • ابزارهای طراحی برای اجرای طرح‌بندی OpenType خود نیاز به دسترسی به بایت‌های فونت دارند و به ابزارهای طراحی اجازه می‌دهند تا در سطوح پایین‌تر، برای اقداماتی مانند انجام فیلترهای برداری یا تبدیل‌ها بر روی اشکال حروف، قلاب شوند.
  • توسعه دهندگان ممکن است پشته های فونت قدیمی برای برنامه های خود داشته باشند که در وب می آورند. برای استفاده از این پشته ها، معمولاً نیاز به دسترسی مستقیم به داده های فونت دارند، چیزی که فونت های وب ارائه نمی دهند.
  • ممکن است برخی از فونت ها برای تحویل از طریق وب مجوز نداشته باشند. برای مثال، Linotype مجوزی برای برخی از فونت‌ها دارد که فقط شامل استفاده از دسکتاپ می‌شود.

Local Font Access API تلاشی برای حل این چالش هاست. از دو بخش تشکیل شده است:

  • یک API شمارش فونت ، که به کاربران اجازه دسترسی به مجموعه کامل فونت‌های موجود سیستم را می‌دهد.
  • از هر نتیجه شمارش، امکان درخواست دسترسی به ظرف SFNT سطح پایین (بایت محور) که شامل داده های کامل فونت است.

پشتیبانی از مرورگر

پشتیبانی مرورگر

  • کروم: 103.
  • لبه: 103.
  • فایرفاکس: پشتیبانی نمی شود.
  • سافاری: پشتیبانی نمی شود.

منبع

نحوه استفاده از 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);
}

اگر فقط به زیرمجموعه‌ای از فونت‌ها علاقه دارید، می‌توانید با افزودن یک پارامتر postscriptNames ، آنها را بر اساس نام‌های PostScript فیلتر کنید.

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 مربوطه ثبت کنید یا افکار خود را به یک مشکل موجود اضافه کنید.

گزارش مشکل در اجرا

آیا اشکالی در پیاده سازی کروم پیدا کردید؟ یا اجرا با مشخصات متفاوت است؟ یک اشکال را در new.crbug.com ثبت کنید. مطمئن شوید که تا جایی که می توانید جزئیات، دستورالعمل های ساده برای بازتولید را وارد کنید و Blink>Storage>FontAccess در کادر Components وارد کنید. Glitch برای به اشتراک گذاری سریع و آسان تکرارها عالی عمل می کند.

پشتیبانی از API را نشان دهید

آیا قصد دارید از Local Font Access API استفاده کنید؟ پشتیبانی عمومی شما به تیم Chrome کمک می‌کند ویژگی‌ها را اولویت‌بندی کند و به سایر فروشندگان مرورگر نشان می‌دهد که چقدر حمایت از آنها ضروری است.

با استفاده از هشتگ #LocalFontAccess یک توییت به @ChromiumDev ارسال کنید و به ما اطلاع دهید که کجا و چگونه از آن استفاده می کنید.

قدردانی ها

مشخصات Local Font Access API توسط Emil A. Eklund ، Alex Russell ، Joshua Bell و Olivier Yiptong ویرایش شده است. این مقاله توسط Joe Medley , Dominik Röttsches و Olivier Yiptong بررسی شده است . تصویر قهرمان توسط برت جردن در Unsplash .