في جملة واحدة
عملية تحويل الخطوط واقتطاعها (Subsetting) تشبه تجهيز شنطتك لرحلة في الويك إند: بدلاً من سحب شنطة سفر مليانة بـ 6,000 حرف فيها نصوص سيريلية ورموز (dingbats) مستحيل تستخدمها، أنت بتعبي بس الحروف اللي محتاجها بالمللي في شنطة ظهر مضغوطة وجاهزة للويب.
المشكلة اللي بتحلها
لو كنت بتعمل مواقع في 2005، كانت خياراتك في التايبوجرافي أشبه بعملية احتجاز رهائن. كان عندك Arial، Times New Roman، Georgia، Verdana، وممكن Comic Sans لو كنت من هواة تدمير الذوق العام. دي كانت خطوط "آمنة للويب" (web-safe)—يعني كنا بنحط إيدينا على قلبنا ونتمنى إنها تكون متثبتة أصلاً على نظام تشغيل المستخدم.
بعدين قامت ثورة الـ @font-face. فجأة، صار بإمكان المصممين تضمين أي خط مخصص يخطر على بالهم. الويب صار شكله حلو، بس كمان صار بطيء بشكل يجلط.
خطوط سطح المكتب العادية (TrueType أو OpenType) مصممة للطباعة وتدعم لغات العالم كلها. ملف .ttf واحد ممكن يحتوي على آلاف الرموز (glyphs)، ويدعم الإنجليزي، اليوناني، الفيتنامي، رموز رياضية متخصصة، وعشرين شكل مختلف لعلامة الـ ampersand (&). الكلام ده ممتاز لبرنامج معالج نصوص، بس يعتبر كارثة لمتصفح ويب شغال على اتصال 3G تعبان. تحميل ملف خط بحجم 400KB بيعمل بلوك للريندر (rendering)، وبيسبب اللحظة المرعبة اللي بيظهر فيها النص بخط افتراضي قبيح (FOUT) أو الأسوأ، النص يكون مخفي تماماً (FOIT).
كنا محتاجين حاجتين عشان نعالج السمنة المفرطة في الخطوط دي:
- ضغط أفضل (Better compression) مصمم خصيصاً للويب (ومن هنا ظهرت صيغ زي WOFF و WOFF2).
- اقتطاع (Subsetting)، وهو التدخل الجراحي لإزالة كل حرف وجدول لغة الموقع بتاعك مش محتاجه فعلياً.
إزاي بتشتغل تحت الكبوت
عشان تفهم إزاي بنصغر حجم الخطوط، لازم تفهم إيه هو ملف الخط أصلاً. الخط الحديث (زي TTF أو OTF) مش مجرد فولدر فيه رسومات فيكتور (vector). هو عبارة عن قاعدة بيانات معقدة بالنظام الثنائي (binary) مبنية على صيغة كونتينر اسمها SFNT.
تشريح الخط
جوه الـ SFNT كونتينر، البيانات مترتبة في جداول محددة:
glyfأوCFF: رسومات الفيكتور الفعلية (المنحنيات والخطوط اللي بتشكل الحروف).cmap: خريطة الحروف (character map)، اللي بتترجم كود الـ Unicode (زيU+0041لحرف 'A') للرسمة الخاصة بيه في جدول الـglyf.GSUB/GPOS: ميزات الـ OpenType المتقدمة زي الـ ligatures (دمج حرفين زي 'f' و 'i') والـ kerning (المسافات الدقيقة بين أزواج معينة من الحروف).name: البيانات الوصفية (Metadata) زي اسم الخط، حقوق النشر، ومعلومات المصمم.
سحر الـ Subsetting
لما بتعمل subsetting لخط، في parser بيفتح الـ SFNT كونتينر ده. أنت بتديله قائمة بالحروف—ولنفترض مثلاً الأبجدية الإنجليزية الأساسية، الأرقام، وعلامات الترقيم الشائعة.
الـ parser مش بس بيمسح رسومات الفيكتور اللي مش مستخدمة من جدول الـ glyf. ده لازم يعيد بناء قاعدة البيانات دي بالكامل وبدقة. بيكتب الـ cmap من جديد عشان يشيل أكواد الـ Unicode اللي اتلغت. وبيمشط جداول الـ GSUB والـ GPOS عشان يمسح أزواج الـ kerning للحروف اللي مبقتش موجودة، عشان يضمن إن الملف ما يضربش. وفي النهاية، بيحسب الـ memory offsets من جديد لـ headers الملف.
خط عادي بحجم 300KB ممكن ينزل بسهولة لـ 15KB لما تعمله subsetting للحروف اللاتينية الأساسية بس.
حرب الصيغ: WOFF و WOFF2
بمجرد ما الخط يتعمله subset، بيجي وقت الضغط.
| الصيغة | تقنية الضغط | الخلاصة |
|---|---|---|
| TTF / OTF | مفيش (غالباً) | ممتازة لتطبيقات التصميم على الديسكتوب. كارثية لو هتستخدمها للويب. |
| WOFF | Zlib | صيغة الويب المفتوحة الأصلية. كويسة، بس أكل عليها الدهر وشرب. |
| WOFF2 | Brotli | المعيار الحديث. بتعمل تحويل لجداول الخط قبل ما تضغطها. |
صيغة WOFF2 هي الملك المتوج لخطوط الويب بلا منازع. هي مش مجرد بتاخد ملف TTF وتعمله zip. صيغة WOFF2 بتعمل تحويل فيزيائي لجداول الـ SFNT—تحديداً بتجمع أنواع البيانات المتشابهة مع بعض—بحيث إن خوارزمية الضغط اللي تحتها (Brotli) تقدر تلاقي أنماط متكررة أطول. النتيجة؟ أحجام ملفات أصغر بنسبة تصل لـ 30% مقارنة بـ WOFF1، وممكن توصل لـ 95% أصغر من ملف TTF الأصلي لو دمجتها مع الـ subsetting.
تجميع الطبخة مع الـ CSS
بمجرد ما يكون عندك ملف WOFF2 المضغوط جداً والمقتطع، بتعرف المتصفح عليه باستخدام CSS. خاصية unicode-range هنا مهمة جداً. دي بتقول للمتصفح: "نزل الملف ده بس لو كان في حرف في الصفحة بيطابق النطاق ده."
@font-face {
font-family: 'MyCustomFont';
/* Load the highly compressed WOFF2 format */
src: url('mycustomfont-subset.woff2') format('woff2');
/* Only trigger the download if the page uses basic Latin characters */
unicode-range: U+0000-00FF, U+0131, U+0152-0153;
font-display: swap;
}
قصص من أرض الواقع
كارثة "هي مجرد علامة &"
وكالة تصميم راقية كانت بتبني landing page لمطعم فخم. التايبوجرافي بتاع العناوين كان شكله خرافي، والسبب الأساسي إنهم استخدموا خط كيرسيف (cursive) فني وجميل بشكل حصري عشان يكتبوا بيه علامة الـ ampersand (&) في اسم المطعم: "Salt & Ash".
لكن أرقام الأداء في متصفح Lighthouse كانت في الحضيض (أحمر). المطورين اكتشفوا إنهم بيجبروا المستخدمين يحملوا ملف TTF بحجم 250KB عشان بس يعملوا ريندر لحرف واحد. بعد ما دخلوا الخط على أداة subsetter واستخرجوا حرف الـ & فقط (بكود Unicode U+0026)، طلعولنا ملف WOFF2 وزنه مضحك جداً: 800 بايت.
الدرس المستفاد: إوعى تحمل عائلة خطوط كاملة عشان drop-cap ديكوري، أيقونات، أو حروف مفردة. اعمل subsetting بقلب جامد.
الميجابايت متعدد اللغات
شركة SaaS عملت localization لموقعها التسويقي للمستخدمين في اليابان وكوريا الجنوبية. وعشان يحافظوا على هوية البراند، عملوا embed لخط CJK (صيني، ياباني، كوري) محترم جداً. خطوط الـ CJK معروف إنها ضخمة بشكل غبي لأنها بتحتوي على عشرات الآلاف من الرموز. حجم الملف كان 4.5MB.
فجأة، المستخدمين في أمريكا وأوروبا بقوا يستنوا ثواني كتير عشان النص يظهر، لأن المتصفح كان بيحمل 4.5MB من الحروف الآسيوية اللي عمرهم ما هيشوفوها. فريق الهندسة حل الكارثة دي بإنهم عملوا subsetting للخط الأساسي وقسموه لقطع أصغر ("chunks") (ملف WOFF2 للحروف اللاتينية، واحد للـ Hiragana/Katakana، إلخ) واستخدموهم في بلوكات @font-face مع تحديد صارم بخصائص unicode-range. دلوقتي المتصفحات بتحمل بس الجزء الخاص باللاتيني اللي حجمه 15KB للمستخدمين اللي بيقرأوا بالإنجليزي.
الدرس المستفاد: استخدم الـ subsetting والـ unicode-range عشان تخدم الـ chunks بتاعة الخطوط ديناميكياً بناءً على احتياجات لغة المستخدم الفعلية.
أخطاء شائعة وفخاخ
- حذف المسطرة (spacebar) بالغلط: وأنت بتكتب الحروف اللي عايز تعملها subsetting بايدك (مثلاً
abcdefghijklmnopqrstuvwxyz)، كتير من المطورين بينسوا يحطوا حرف المسافة (U+0020). من غيره، خطك المخصص اللي تعبت فيه هيعمل fallback لخط Arial كل ما يكون في مسافة بين الكلمات، والنتيجة بتكون شكل مرعب شبه رسايل التهديد بتاعة الخاطفين (رسايل متجمعة من جرايد مقصوصة). - استخدام صيغ قديمة بدون داعي: كتير من المطورين لسه بيعملوا generate وبيخدموا خطوط بصيغ EOT و TTF و SVG في الـ CSS بتاعهم "من باب الاحتياط". ما تعملش كده. صيغة WOFF2 مدعومة في أكتر من 97% من المتصفحات على مستوى العالم. استخدم WOFF2، وممكن توفر WOFF كـ fallback للمتصفحات العتيقة، ووقف على كده.
- إزالة ميزات OpenType الأساسية: أدوات الـ subsetting العنيفة ساعات بتعرض إنها تمسح جداول
GSUBوGPOSعشان توفر كام كيلوبايت. لو خطك بيعتمد على ligatures معقدة (زي تحويل->لسهم) أو بيعتمد بشكل كبير على الـ kerning عشان ما يبقاش شكله بشع، مسح الجداول دي هيدمر التايبوجرافي بتاعك تماماً. - نسيان
font-display: swap: حتى ملف الـ WOFF2 المقتطع الصغير اللي بحجم 12KB بياخد كام ملي ثانية عشان يتحمل. لو ما حطيتشfont-display: swapفي الـ CSS بتاعك، المتصفحات الحديثة هتخفي النص بتاعك تماماً لحد ما الخط يوصل. إدي للمستخدمين نص بخط النظام يقرؤوه على بال ما خطك المخصص يوصل بالسلامة.
ليه لازم يكون على رادارك
خطوط الويب تاريخياً هي واحدة من أسوأ المجرمين لما نتكلم عن تدمير الـ Web Vitals. لو بتهتم بمؤشرات زي Largest Contentful Paint (LCP) أو Cumulative Layout Shift (CLS)، يبقى لازم تهتم بطريقة توصيل الخطوط (font delivery).
لازم تفكر في الـ subsetting وتحويل الخطوط في نفس اللحظة اللي بتستلم فيها ملف .ttf أو .otf من مصمم أو تحمله من أي منصة خطوط (foundry). استخدام خطوط الديسكتوب الخام على الويب بيعادل بالظبط استخدام صورة bitmap خام مش مضغوطة بحجم 10MB بدل ما تستخدم WebP.
بتحويلك للخط لـ WOFF2 وحذف آلاف الرموز (glyphs) اللي مش بتستخدمها، أنت بتقلل تكاليف الباندويث (bandwidth)، بتقلل البصمة الكربونية للتطبيق بتاعك، وبتتأكد إن موقعك فعلياً جاهز للقراءة في نفس الملي ثانية اللي المستخدم بيكليك فيها على اللينك بتاعك.
تعمق أكتر
- MDN Web Docs: @font-face - المرجع الأساسي لإزاي تطبق خطوط مخصصة وتستخدم
unicode-rangeصح في الـ CSS. - W3C WOFF2 Specification - المواصفة التقنية الرسمية اللي بتشرح بالتفصيل إزاي WOFF2 بيحول ويضغط جداول الـ SFNT.
- RFC 7932: Brotli Compressed Data Format - وثائق IETF لخوارزمية الضغط اللي بتدي WOFF2 قواها الخارقة.
- Web.dev: Optimize WebFonts - دليل جوجل المعتمد لتقليل حجم ملفات خطوط الويب ومنع الـ layout shifts.
- Google Fonts Knowledge: What is a font? - غوص عميق في هيكل جداول الـ SFNT وإزاي الـ glyphs بتتخزن تحت الكبوت.