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

تعرَّف على كيفية السماح لك من خلال 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
  • ‫Edge: 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.