Skip to content

فونت

This content is not available in your language yet.

مرجع زنده. یکان‌بخ برای رابط، وزیرمتن برای چاپ و برای نویسه‌هایی که یکان‌بخ ندارد. منبعِ همه در tools/fonts/ (نسخهٔ منتخبِ هر خانواده) و بستهٔ کاملِ سازنده در tools/fonts/packages/؛ ساختشان scripts/build-fonts.mjs.

سطح فونت پرونده اندازه
رابط Yekan Bakh 3.100، متغیر apps/web/public/fonts/YekanBakh-var.woff2 ۴۳ KB
پرکنندهٔ رابط Vazirmatn، فقط ۸۶ نویسه apps/web/public/fonts/Vazirmatn-gaps-var.woff2 ۱۴ KB
چاپ، وب Vazirmatn 33.003، متغیر apps/web/public/fonts/Vazirmatn-print.woff2 — هنگامِ ساختِ سند جاسازی ۶۷ KB
چاپ، خط فرمان همان بایت‌ها، base64 packages/report/src/fonts.ts (@darzsaz/report/fonts) ۶۷ KB

پیش از این رابط هم وزیرمتن بود: ۶۷ KB. حالا ۴۳ KB برای همهٔ متن، و ۱۴ KB که مرورگر فقط برای همان ۸۶ نویسه به کار می‌برد. سرویس‌ورکر هر سه را پیش‌انباشت می‌کند (۱۲۴ KB)؛ تا نسل ششم فونتِ چاپ base64 درونِ جاوااسکریپتِ وب بود — ۶۸ KB (gzip) از بودجهٔ js ِ هر کاربر، چاپ بکند یا نه — و حالا پروندهٔ جداست که apps/web/src/lib/print-font.ts یک بار در هر نشست می‌خواند و درونِ هر سند می‌نشاند (نقشهٔ نسل ششم، ۰.۱). scripts/size-budget.mjs برگشتنِ base64 به تکه‌های js را خطا می‌گیرد. print-font.ts ِ گزارش (خانواده، بازهٔ وزن، نامِ پرونده، سازندهٔ @font-face) و fonts.ts هر دو تولیدی‌اند.

خواستهٔ اصلی: فارسی و انگلیسیِ کنارش با هم بخوانند. در این برنامه «چاپ برشکار (PDF)»، «نستینگ CNC»، «برون‌ریزی JSON» و «Ctrl+S» وسط جملهٔ فارسی‌اند. هفت نامزدِ متنی از کتابخانه در کروم کشیده و اندازه گرفته شدند (۱۴۰۵/۰۶/۲۲):

فونت الف ÷ حرف بزرگ ضخامت الف ÷ I (۴۰۰ / ۷۰۰) تیرگی انگلیسی ÷ فارسی (۴۰۰ / ۷۰۰) tnum زیرمجموعه
Yekan Bakh 1.00 0.96 / 0.95 1.09 / 1.04 43 KB
Dana 0.93 1.25 / 1.13 1.11 / 1.09 59 KB
Morabba 0.88 0.91 / 0.92 1.15 / 1.05 32 KB
IRANYekanX 0.91 0.84 / 0.91 1.21 / 1.11 69 KB
Anjoman Max 1.00 0.91 / 0.86 1.22 / 1.16 56 KB
Vazirmatn (پیشین) 0.95 0.88 / 0.84 1.23 / 1.22 66 KB
Peyda 0.94 0.85 / 0.85 1.27 / 1.16 71 KB
  • الف ÷ حرف بزرگ: ارتفاع الف به ارتفاع H. یک یعنی حرف بزرگ لاتین درست هم‌قدِ الف است.
  • ضخامت: پهنای الف به پهنای I در همان وزن. یک یعنی خط هر دو خط یکی است.
  • تیرگی: جوهرِ یک جملهٔ انگلیسی به جوهرِ یک جملهٔ فارسی، هم‌اندازه و هم‌وزن، از عکسِ کروم. ۱٫۲۳ یعنی واژهٔ لاتین ۲۳٪ سیاه‌تر از فارسیِ دورش می‌نشیند و از جمله بیرون می‌زند.

وزیرمتن، ایران‌یکان‌X و دانا اندازه‌های لاتینِ یکسان دارند: ارتفاع x 0.528 و حرف بزرگ 0.711 در هر سه — همان لاتینی که وزیرمتن از Roboto گرفته. لاتینِ یکان‌بخ (0.463 و 0.647) برای خودش کشیده شده، و در جدول همین پیداست.

tnum لازم است، نه تزئینی. رقم‌های فارسیِ پیش‌فرض هم‌عرض نیستند (یکان‌بخ ۲۶۰ تا ۷۰۰ واحد)؛ ستونِ جدول برش بی tnum صاف نمی‌ایستد و عددی که زنده عوض می‌شود می‌رقصد. در یکان‌بخ tnum زیر خط arab هم ثبت شده و رقم فارسی را ۷۰۰ و لاتین را ۵۵۰ می‌کند.

  • Peyda — جدیدترین (۲۰۲۵)، ولی بی tnum: رقم‌های هر دو خط متناسب‌اند و «۱۱۱٬۱۱۱» در ستون جمع می‌شود. بدترین تیرگیِ لاتین در وزن ۴۰۰.
  • IRANYekanX و DanafsType=256 یعنی سازنده زیرمجموعه‌سازی را در خودِ فونت منع کرده؛ و tnum ندارند. دانا ` و § و · را هم ندارد.
  • Morabba — فونت تیتر است: «۷» و «۸» اش شکلِ U و n دارند؛ برای برنامه‌ای که همه‌اش اندازه است، خطرناک.
  • Anjoman Max — ضخامت خوب، ولی لاتین ۲۲٪ تیره‌تر.

با فونت متغیر، وزن ۸۰۰ همان کنتراست تیتر را رایگان می‌دهد. در نمونهٔ «درزساز Darzsaz» با یکان‌بخ ۸۰۰ هر دو خط هم‌وزن‌اند؛ فونت دوم یعنی درخواست دوم و یک ناهماهنگیِ تازه بین تیتر و متن.

ضعف‌های یکان‌بخ — و با هر کدام چه کردیم

Section titled “ضعف‌های یکان‌بخ — و با هر کدام چه کردیم”
ضعف اثر کار
منهای ریاضی (U+2212) ندارد Intl روی هر عدد منفیِ فارسی همین را می‌نویسد: «‎−۱۲» پرکنندهٔ وزیرمتن با unicode-range
` ^ ~ § ² و لاتینِ تکیه‌دار ندارد «~۵۰»، «m²»، نامِ «Café» ِ کاربر همان پرکننده (۸۶ نویسه)
ارتفاع x ِ لاتین کمتر (0.463 در برابر 0.528) رابط انگلیسی کمی ریزتر سنجیده در ۱۲ تا ۱۴ پیکسل، DPR ۱: پهنای سطر برابرِ وزیرمتن، خوانا — تغییری نکرد
hinting ندارد شاید لبه‌های نرم‌تر روی نمایشگرِ کم‌تراکمِ ویندوز روی ویندوز سنجیده نشده. وزیرمتن هم فقط prep/gasp داشت؛ اگر آنجا نرم دیده شد، جای پیگیری همین ردیف است
رقم فارسیِ tnum پهن است (۷۰۰) ستون عددی کمی باز همان وضعِ وزیرمتن؛ tnum فقط روی ستون و عددِ زنده است، نه متن روان
تجاری است مجوز پایین‌تر

چرا به خودِ یکان‌بخ نویسه اضافه نکردیم: افزودن گلیف یا نگاشت به cmap یعنی ویرایشِ فونت، که مجوز fontiran اجازه نمی‌دهد. زیرمجموعه‌سازی ویرایش نیست و fsType=8 ِ خودِ فونت اجازه‌اش را داده.

سند چاپی از سایت بیرون می‌رود: دانلود HTML، اشتراک در واتساپ، و CLI روی npm که @darzsaz/report را با فونتش در خود دارد (apps/cli/dist/darzsaz.mjs همین base64 را دارد). فونتِ جاسازی‌شده یعنی پخشِ خودِ پروندهٔ فونت. مجوز fontiran فقط استفاده روی سایتِ ثبت‌شده است؛ وزیرمتن SIL OFL و پخشش آزاد.

این مسیر عمداً پیکربندی‌پذیر نیست — پرچمی نیست که کسی روزی بزند و فونت تجاری را به npm بفرستد.

یکان‌بخ و بقیهٔ فونت‌های tools/fonts/ جز وزیرمتن تجاری‌اند:

  • فونت‌ها را صاحبِ مخزن خریده؛ licenses.pdf و شرایط-استفاده.pdf کنار هر خانواده‌اند (Peyda فقط شرایط-استفاده.pdf).
  • مجوز برای وب‌سایت و نرم‌افزار به نام همان محصول صادر می‌شود. انتشار خودکار روی GitHub Pages خاموش است (deploy.yml فقط دستی)؛ روشن کردنش مجوزِ وبِ درزساز می‌خواهد.
  • FontLicense.txt در ۱۳ پوشه هست (یکان‌بخ ندارد)؛ ۱۱ تا جای کدِ شش‌رقمی را خالی دارند ((.....))، و در iran-marker و titr-zebr جای کد نیست: متنشان استفادهٔ شخصیِ رایگان است، بی اجازهٔ فروش یا انتشار.
  • مخزن خصوصی است؛ apps/cli عمومی روی npm منتشر می‌شود و هیچ فونت تجاری در آن نیست.
Terminal window
pnpm format:fonts # هر سه خروجی + بلوک index.html
node scripts/build-fonts.mjs --check # در verify و CI

pyftsubset از fontTools لازم است، با نسخهٔ دقیقِ scripts/requirements.txt (--check بایت‌به‌بایت می‌سنجد و نسخهٔ دیگر بایتِ دیگر می‌سازد) — وابستگی npm نیست: زیرمجموعه‌سازی کارِ گاه‌به‌گاهِ ساخت است.

  • بازهٔ وزن و unicode-range از خودِ فونت خوانده می‌شوند. بلوکِ @font-face میان <!-- fonts:start --> و <!-- fonts:end --> در apps/web/index.html تولیدی است و از prettier می‌گذرد تا format:check با آن دعوا نکند.
  • پرکننده محاسبه می‌شود، نه فهرست دستی: نویسه‌های UNICODES که یکان‌بخ ندارد و وزیرمتن دارد. فونتِ رابط که عوض شود، پرکننده خودش عوض می‌شود.
  • پرونده‌ای که دیگر ساخته نمی‌شود پاک می‌شود، و --check آن را خطا می‌داند: سرویس‌ورکر هر woff2 ِ آن پوشه را پیش‌انباشت می‌کند، پس فونت مرده یعنی بایتِ مرده روی گوشیِ هر کاربر.
  • نام بدون کروشه. Vazirmatn[wght].ttf نامِ قراردادیِ مبدأ است، ولی [ و ] در URL رزروشده‌اند؛ سرور ایستای خودمان %5B را دیکد نمی‌کرد و پنج آزمون e2e با ۴۰۴ افتادند.

scripts/font-coverage.mjs برای هر سطح با فونتِ خودش می‌سنجد که هر نویسهٔ دیدنی گلیف دارد: رابط با یکان‌بخ + پرکننده، چاپ با وزیرمتنِ جاسازی‌شده.

«دیدنی» یعنی رشته. نسخهٔ اول همهٔ نویسه‌های پرونده را می‌شمرد. با یکان‌بخ ۲۷۶ پرونده به‌خاطر ِ template literal می‌افتادند، و ۹ تا از ۱۸ نویسهٔFALLBACK` (فلش و خط‌های نمودار) فقط در کامنت بودند. حالا پارسرِ خودِ TypeScript فقط رشته و متن JSX را می‌دهد، به‌علاوهٔ:

  • JSONهای کاتالوگ — نام مصالح و یراق به رابط و چاپ می‌رسند و نسخهٔ اول اصلاً نمی‌خواندشان؛
  • خروجیِ Intl برای هر زبانِ LOCALES — منهای U+2212 در هیچ رشته‌ای نیست ولی روی هر عدد منفی دیده می‌شود؛
  • msgstr ِ کاتالوگ‌های ترجمه و content: ِ CSS.

بی پرکننده، نگهبان را در StatusBar و IssuesPanel، ~ را در قواعد یراق و ² را در لیست برش نشان می‌دهد (امتحان‌شده).

۴ نویسه هنوز با فونت سامانه‌اند و در FALLBACK با دلیل فهرست‌اند: ← ↻ ⌀ ⌘ — هیچ‌کدام از دو فونت ندارندشان؛ جای درستشان نقشِ SVG است.

apps/cli بیرون است: خروجی‌اش با فونتِ پایانهٔ کاربر کشیده می‌شود.

apps/web/e2e/fonts.spec.ts از پروتکل کروم (CSS.getPlatformFontsForNode) می‌پرسد هر گلیف را واقعاً کدام فونت کشیده:

  • تیتر خانه و جملهٔ فارسیِ با PDF/CNC/Ctrl+S → همه یکان‌بخ؛
  • «‎−۱٬۲۳۴» → رقم‌ها یکان‌بخ، فقط یک گلیف (منها) وزیرمتن.

بی @font-face ِ پرکننده آزمون دوم می‌افتد و نام فونتِ مقصر را می‌گوید («Liberation Sans»، فونت سامانه). jsdom و axe هیچ‌کدام این را نمی‌بینند.

tabular-nums فقط روی ستون‌ها و عددهای زنده است — جدول‌ها، اندازه‌های روی بوم، دلتای نوار وضعیت، فیلد عددی — نه روی ریشه. روی ریشه که بود، عددِ داخلِ متنِ روان («۲ ورق») با فاصله‌های باز چاپ می‌شد؛ با اجرای واقعیِ اپ پیدا شد.