دفتر · ملاحظة 002 · الطباعة

عشر لغات، ثلاثة ملفات خطوط

أول ما ينهار عند إطلاق موقع بعشر لغات هو ميزانية الخطوط. هنا لم تنهَر. لكننا دفعنا تكلفة أخرى لدعم الحروف السيريلية والعربية، ولم نخفها.

Serhat Belen

مؤسس BLN Global · · قراءة 6 دقائق

الجواب المختصر

لو حمّلت الخطوط الثلاثة نفسها من Google Fonts، لاحتاجت الصفحة التركية إلى 6 ملفات بحجم 250 KB من مصدرين خارجيين. من خادمنا تحمّل 3 ملفات بحجم 165 KB من مصدر واحد. جاء معظم التوفير من تثبيت المحاور غير المستخدمة، لا من تقليص مجموعة المحارف. اضطررنا إلى اختيار عائلة منفصلة للحروف السيريلية والعربية. وفي العربية تظهر بعض الرموز بخط بديل.

اعتمدت طباعة الموقع على ثلاث عائلات: Archivo للعناوين، Instrument Sans للنص، وMartian Mono للأرقام والوسوم. الثلاثة خطوط متغيرة. مع خمس لغات لم تظهر مشكلة. عند الانتقال إلى عشر لغات كبرت مشكلتان معًا: حجم التنزيل وتغطية الحروف.

ما الذي قارنّاه بماذا

لن تكون مقارنة ملفات TTF الخام بملفات WOFF2 التي نشرناها منصفة. معظم الفرق يأتي من الضغط، لا من تقليص مجموعة المحارف. المقارنة المفيدة تكون مع البديل الفعلي: ما حجم التنزيل لو جاءت عائلات الخطوط الثلاث نفسها من Google Fonts؟

لا ينزّل المتصفح كل الملفات التسعة. unicode-range يفحص الحقل ويحمّل المجموعات الفرعية التي تحتاجها الصفحة فقط. في الصفحة التركية، يعني ذلك latin + latin-ext لكل عائلة خطوط:

latin 88.0 KB <- latin-ext 83.8 KB <- vietnamese 33.6 KB latin 29.2 KB <- latin-ext 10.8 KB <- latin 23.0 KB <- latin-ext 15.5 KB <- cyrillic 10.3 KB cyrillic-ext 3.1 KB ما ستنزّله الصفحة التركية: 250 KB (6 ملفات)
سحبنا CSS من Google Fonts، وقرأنا حقل unicode-range في كل كتلة @font-face، ثم قسنا الملفات واحدًا واحدًا. الملفات التي تحمل سهمًا ينزّلها المتصفح فعلًا في صفحة تركية.
250 KB / 6 ملفات / مصدران خارجيان165 KB / 3 ملفات / مصدر واحد

حِمل الخطوط في الصفحة التركية

كيف قسناه اليسار هو القياس أعلاه. اليمين هو الموجود في هذا المستودع archivo.woff2 + instrument.woff2 + martian.woff2 الحجم الفعلي لملفاته على القرص.

لم نكسب البايتات وحدها. انخفضت الطلبات من ستة إلى ثلاثة، واختفت مصافحة DNS + TLS مع أصلين خارجيين بالكامل. كيف أغلقنا مشكلة المورد الذي كان يحجب الرسم الأول في ملاحظة آخر 18 نقطة يشرح ذلك.

ثلاثة فخاخ

الأولى: لا تضم مجموعة latin-ext أحرف اللاتينية الأساسية

في المحاولة الأولى، نزّلنا ملف latin-ext من Google Fonts وقلّصناه. احتوى الملف الناتج على 130 محرفًا من دون أرقام. السبب بسيط: latin-ext طبقة تُضاف فوق latin، وهي إضافة هو مجموعة فرعية، وليس أبجدية كاملة بمفرده. نزّل الخط المتغير كاملًا من مستودع google/fonts، ثم استخرج المجموعة الفرعية بنفسك.

الثانية: إن لم تثبّت المحاور غير المستخدمة، يكبر الملف خمسة أضعاف

كل محور في الخط المتغيّر يزيد وزن الملف. التصميم يستخدم الوزن والعرض فقط. إن لم تثبّت بقية المحاور على قيمها الافتراضية، تبقى بياناتها كلها داخل الملف.

tam = {a.axisTag: a.defaultValue for a in t['fvar'].axes if a.axisTag not in eksen} tam.update(eksen) # نثبت المحاور عدا wght/wdth على قيمها الافتراضية، # وإلا يكبر الملف خمسة أضعاف
تثبيت المحور قبل تقليل الخط وفّر مساحة أكبر من تقليله وحده.

ثالثًا: يتأخر تحميل gvar

بعد تثبيت المحور عبر fontTools، حين حاولنا تقليل المجموعة مباشرة KeyError: space نأخذها. السبب هو التحميل الكسول لبيانات الغليف المتغيرة (gvar): بعد التثبيت يبدو الكائن متسقًا في الذاكرة، لكن أداة أخذ الجزء لا تقرأه. الحل ملتف لكنه سطر واحد: احفظ الملف مؤقتًا بصيغة TTF، افتحه من جديد، ثم خذ الجزء المطلوب.

السيريلية والعربية: الكلفة المدفوعة

لا يدعم Archivo الحروف السيريلية، ولا Instrument Sans. ولا يدعم أي منهما الحروف العربية. لذلك احتجنا إلى عائلة خط منفصلة لهاتين اللغتين، ولم نخترها اعتباطًا.

  • الروسية: Roboto Flex. كان التطابق البنيوي الوحيد هناك: محور العرض موجود. أي إن كل font-variation-settings تعمل القيم دون أي تغيير. يخدم ملف واحد العناوين والنص، وتبقى الصفحة الروسية أخف من الصفحة اللاتينية.
  • العربية: Noto Sans Arabic. الخط الوحيد الذي يضم محورًا للعرض. حجم الملف الواحد 144 KB ويؤدي ثلاثة أدوار، لذلك تحمّل الصفحة العربية بيانات أقل من الصفحة اللاتينية.

الكلفة هنا: في Noto Sans Arabic و لا يضم الخط هذين الرمزين. في الصفحة العربية يأتيان من الخط البديل، لذلك يبدوان مختلفين قليلًا عما حولهما. لم نخفِ الأمر. كتبنا تعليقًا في CSS كي لا يراه المطور التالي ويحسبه خطأً.

يحتاج تنسيق اليمين إلى اليسار إلى عمل مستقل. عكسنا اتجاهات الأسهم واستبدلنا خصائص الموضع بنظائرها المنطقية (margin-inline-start, inset-inline-start)، كي تعمل CSS نفسها بشكل صحيح في الاتجاهين.

تعديل صغير: لماذا جعلنا Martian Mono اختياريًا

اثنتان من عائلات الخطوط الثلاث font-display:swap يستخدم Martian Mono. اختياري. السبب قسناه: مع swap يصل Martian متأخرًا، فيجبر زر القائمة على إعادة القياس ويصنع انزياحًا في التخطيط قدره 0,015. بما أننا نحمله مسبقًا، فهو يلحق غالبًا. وإذا لم يلحق في الحالة الوحيدة، لا تتحرك الصفحة وتبقى على الخط البديل.

حجم مجلد الخطوط لعشر لغات هو 404 KB. لن يحمّله أي زائر كاملًا. كل صفحة تطلب ملفات لغتها فقط.

الأسئلة الشائعة

هل أستضيف الخطوط بنفسي بدل استخدام Google Fonts؟

من جهة الحجم، ليس دائمًا. من جهة الاتصال، غالبًا نعم. Google Fonts يتصل بمصدرين مختلفين، وكل مصدر جديد يعني حل DNS ومصافحة TLS. عندنا ظهر الفرق هكذا: بدل 250 KB / 6 ملفات / مصدرين صار 165 KB / 3 ملفات / مصدر واحد.

ما الذي يوفّر أكثر: تقليل الخط أم تثبيت المحور؟

ثبّت المحور. كل محور لا تستخدمه في الخط المتغيّر يشغل مساحة داخل الملف. إن لم تثبّته، قد يكبر الملف عدة مرات. بعدها يأتي تقليص المحارف.

هل تكفي مجموعة latin-ext للتركية؟

لا، لا تكفي وحدها لأي لغة. latin-ext مجموعة إضافية فوق latin، ولا تحتوي على الحروف الأساسية أو الأرقام. نزّل الخط المتغير كاملًا، ثم استخرج مجموعة المحارف التي تحتاج إليها بنفسك.

هل نستخدم swap أم optional في font-display؟

إذا كان النص يشكّل جسم الصفحة وكنت تحمّل الخط مسبقًا، فخيار optional أأمن: إن تأخر الخط، لا تتحرك الصفحة وتبقى على الخط البديل. عندنا، كان swap يسبب انزياحًا في التخطيط قدره 0,287 في الصفحات العربية. optional خفّضه إلى صفر.

أي خط اخترت للعربية والروسية، ولماذا؟

اخترنا Roboto Flex للروسية وNoto Sans Arabic للعربية. السبب بنيوي لا جمالي: لدى الخطين محور عرض، أي إن الموجود في CSS font-variation-settings يعمل من دون تغيير القيم.

المصادر

أعمال ذات صلة