استخدام أسلوب الخط المتقدم مع الخطوط المحلية

تعرَّف على كيفية السماح لك من خلال Local Font Access API بالوصول إلى الخطوط المثبَّتة على الجهاز لدى المستخدم والحصول على تفاصيل منخفضة المستوى عنها.

الخطوط الآمنة على الويب

إذا كنت تطوِّر الويب منذ فترة كافية، قد تتذكر ما يُعرف باسم الخطوط الآمنة على الويب. من المعروف أنّ هذه الخطوط متاحة في جميع حالات أنظمة التشغيل الأكثر استخدامًا تقريبًا (تحديدًا، Windows وmacOS وتوزيعات Linux الأكثر شيوعًا وAndroid وiOS). في أوائل العقد الأول من القرن الحادي والعشرين، كانت شركة 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() في أنّه يمكن إساءة استخدامها لإنشاء بصمة المتصفّح. تبيّن أنّ قائمة الخطوط التي ثبَّتها المستخدم يمكن أن تكون محدّدة الهوية. كثير من الشركات لديها خطوط خاصة بها مثبتة على أجهزة الكمبيوتر المحمولة للموظفين. على سبيل المثال، تستخدم Google خطًا للشركة باسم Google Sans.

تطبيق Font Book في نظام التشغيل macOS يعرض معاينة لخط Google Sans
خط Google Sans المثبّت على الكمبيوتر المحمول الخاص بموظف في Google

يمكن للمهاجم محاولة تحديد الشركة التي يعمل بها أحد الأشخاص من خلال اختبار توفّر عدد كبير من خطوط الشركات المعروفة، مثل Google Sans. سيحاول المهاجم عرض النص المكتوب بهذه الخطوط على لوحة وقياس الرموز. إذا كانت الرموز تتطابق مع الشكل المعروف لخط الشركة، سيصل المهاجم إلى ما يريده. إذا لم تتطابق الأحرف الرسومية، سيعرف المهاجم أنّه تم استخدام خط بديل تلقائي لأنّ خط الشركة لم يتم تثبيته. للاطّلاع على التفاصيل الكاملة عن هذه الهجمات وغيرها من هجمات وضع بصمة المتصفّح، يُرجى قراءة الدراسة التي أجراها Laperdix وآخرون.

يمكن تحديد خطوط الشركة بشكل منفصل، حتى قائمة الخطوط المثبتة فقط. أصبح الوضع المتعلّق بمسار الهجوم هذا سيئًا للغاية لدرجة أنّ فريق WebKit قرر مؤخرًا "تضمين خطوط الويب والخطوط التي تأتي مع نظام التشغيل فقط [في قائمة الخطوط المتاحة]، ولكن ليس الخطوط التي ثبّتها المستخدم محليًا". (وأنا هنا، مع مقالة حول منح حق الوصول إلى الخطوط المحلية).

واجهة برمجة التطبيقات Local Font Access API

ربما تكون بداية هذه المقالة قد أصابتك بشعور سلبي. هل يمكننا فعلاً عدم الحصول على أشياء لطيفة؟ لا داعي للقلق. نعتقد أننا نستطيع، وربما كل شيء على ما يرام. لكن أولاً، لأجيب عن سؤال تطرحه على نفسك.

لماذا نحتاج إلى واجهة برمجة تطبيقات Local Font Access API عند توفُّر خطوط ويب؟

لطالما كان من الصعب توفير أدوات تصميم ورسومات بجودة احترافية على الويب. كانت إحدى العقبات هي عدم القدرة على الوصول إلى المجموعة الكاملة المتنوعة من الخطوط التي تم إنشاؤها بشكل احترافي والملمح بها التي ثبّتها المصممون محليًا. تتيح خطوط الويب بعض حالات استخدام النشر، ولكنها لا تتيح الوصول الآلي إلى أشكال الرموز المتجهّة وجداول الخطوط التي تستخدمها أدوات معالجة الرسوم الممسوحة ضوئيًا لعرض الخطوط العريضة للرموز. وبالمثل، لا توجد طريقة للوصول إلى البيانات الثنائية لخط ويب.

  • تحتاج أدوات التصميم إلى الوصول إلى وحدات البايت الخاصة بالخطوط لتنفيذ تنسيق OpenType الخاص بها والسماح لأدوات التصميم بجذب العناصر عند مستويات أقل، وذلك لتنفيذ إجراءات مثل تنفيذ فلاتر المتجهات أو عمليات التحويل على الأشكال الرسومية.
  • قد يكون لدى المطوّرين مجموعات خطوط قديمة لتطبيقاتهم التي ينقلونها إلى الويب. لاستخدام هذه الحزم، عادة ما تتطلب وصولاً مباشرًا إلى بيانات الخط، وهو شيء لا تقدمه خطوط الويب.
  • قد لا تكون بعض الخطوط مرخصة للتسليم عبر الويب. على سبيل المثال، تمتلك شركة Linotype ترخيصًا ل بعض الخطوط التي تتضمّن فقط استخدام أجهزة الكمبيوتر المكتبي.

تهدف Local Font Access 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 من خلال طريقة 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 لعرض المعلومات اللازمة فقط لتفعيل حالات الاستخدام المذكورة، وذلك كلما أمكن ذلك. قد تعرِض واجهات برمجة تطبيقات النظام قائمة بالخطوط المثبَّتة ليس بترتيب random أو بترتيب أبجدي، ولكن بترتيب تثبيت الخطوط. يمكن أن يؤدي عرض قائمة الخطوط المثبَّتة المقدمة من واجهة برمجة تطبيقات النظام هذه إلى الكشف عن بيانات إضافية يمكن استخدامها لملفات مرجعية، ولا تتم الاستفادة من حالات الاستخدام التي نريد تفعيلها من خلال الاحتفاظ بهذا الترتيب. نتيجةً لذلك، تتطلّب واجهة برمجة التطبيقات هذه ترتيب البيانات المعروضة قبل عرضها.

الأمان والأذونات

لقد صمم فريق Chrome واجهة برمجة التطبيقات Local Font Access API ونفّذها باستخدام المبادئ الأساسية المحدّدة في مقالة التحكّم في الوصول إلى ميزات Web Platform الفعّالة، بما في ذلك التحكّم الذي يمارسه المستخدم والشفافية وسهولة الاستخدام.

التحكّم في المستخدم

يتحكم المستخدمون بشكل كامل في إمكانية الوصول إلى الخطوط الخاصة بهم ولن يُسمح بذلك إلا بعد منح الإذن "local-fonts"، كما هو موضّح في ملف قاعدة بيانات الأذونات.

الشفافية

سيظهر في ورقة معلومات الموقع الإلكتروني ما إذا كان قد تم منح موقع إلكتروني إذن الوصول إلى الخطوط المحلية للمستخدم.

استمرار الإذن

سيستمر تطبيق إذن ""local-fonts"" بين عمليات إعادة تحميل الصفحات. ويمكن إلغاؤه من خلال جدول معلومات الموقع الإلكتروني.

ملاحظات

يريد فريق Chrome معرفة تجاربك مع واجهة برمجة التطبيقات Local Font Access API.

أخبِرنا عن تصميم واجهة برمجة التطبيقات.

هل هناك مشكلة في واجهة برمجة التطبيقات لا تعمل على النحو المتوقّع؟ هل هناك طُرق أو سمات مفقودة تحتاجها لتنفيذ فكرتك؟ هل لديك سؤال أو تعليق بشأن نموذج الأمان؟ يمكنك الإبلاغ عن مشكلة في المواصفات في مستودع GitHub المقابل، أو إضافة ملاحظاتك إلى مشكلة حالية.

الإبلاغ عن مشكلة في التنفيذ

هل رصدت خطأ في عملية تنفيذ Chrome؟ أم أن التنفيذ يختلف عن المواصفات؟ يمكنك الإبلاغ عن خلل على الرابط new.crbug.com. احرص على تضمين أكبر قدر ممكن من التفاصيل، وتعليمات بسيطة لإعادة إنتاج الخلل، وأدخِل Blink>Storage>FontAccess في مربّع المكوّنات. يُعدّ تطبيق Glitch مثاليًا لمشاركة عمليات إعادة الإنتاج بسرعة وسهولة.

إظهار الدعم لواجهة برمجة التطبيقات

هل تخطّط لاستخدام Local Font Access API؟ يساعد دعمك العلني فريق Chrome في تحديد الميزات التي يجب أن تحظى بالأولوية، ويُظهر لموفّري المتصفّحات الآخرين مدى أهمية توفير هذه الميزات.

أرسِل تغريدة إلى ‎@ChromiumDev باستخدام الهاشتاغ #LocalFontAccess وأخبِرنا بمكان استخدامك للميزة وطريقة استخدامك لها.

الشكر والتقدير

تم تعديل مواصفات Local Font Access API بواسطة إيميل أ. Eklund، Alex Russell، Joshua Bell، Olivier Yiptong تمت مراجعة هذه المقالة من قِبل جو ميديل، دومينيك روتشس، و أوليفير يبيتونغ. الصورة الرئيسية من أعمال Brett Jordan على Unsplash.