بارگذاری فونت سفارشی از سرور خودمان: @font-face و Variable Fonts

در درس ۸-۱ به‌طور مختصر به @font-face اشاره کردیم و گفتیم این روش، برای وقتی‌ست که فایل فونت رو خودمون مستقیماً میزبانی می‌کنیم، نه از طریق یک سرویس خارجی مثل Google Fonts. تو این درس، این قانون رو با تمام جزئیاتش می‌بینیم و در ادامه با مفهوم جدیدتر و قدرتمند Variable Fonts هم آشنا می‌شیم.

@font-face چیست؟

@font-face یک قانون CSS‌ه که به مرورگر می‌گه: «یک فونت سفارشی با این اسم دلخواه وجود داره، و فایلش رو از این آدرس دانلود کن». بعد از این تعریف، می‌شه از اون اسم دلخواه، دقیقاً مثل هر فونت دیگه‌ای، داخل font-family استفاده کرد.

Syntax پایه

@font-face {
  font-family: "Vazirmatn";
  src: url("fonts/Vazirmatn-Regular.woff2") format("woff2");
}

body {
  font-family: "Vazirmatn", sans-serif;
}

در این مثال، دو کار انجام شده: اول با @font-face، اسم دلخواه Vazirmatn رو به یک فایل فونت مشخص وصل کردیم؛ بعد در Rule دوم، دقیقاً مثل هر فونت دیگه‌ای، این اسم رو داخل font-family استفاده کردیم.

Propertyهای اصلی داخل @font-face

font-family: نام دلخواه فونت

@font-face {
  font-family: "MyBrandFont";
  src: url("brandfont.woff2") format("woff2");
}

این نام کاملاً دلخواهه؛ نیازی نیست دقیقاً با نام واقعی فونت (که ممکنه در فایل فونت ثبت شده باشه) یکسان باشه، هرچند برای وضوح بیشتر معمولاً همون نام اصلی انتخاب می‌شه.

src: آدرس فایل و فرمت آن

@font-face {
  font-family: "MyFont";
  src: url("myfont.woff2") format("woff2"),
       url("myfont.woff") format("woff");
}

Property به اسم src می‌تونه چند فایل مختلف رو، هرکدوم با فرمت متفاوت، به‌عنوان جایگزین معرفی کنه. مرورگر این لیست رو از چپ به راست بررسی می‌کنه و اولین فرمتی که پشتیبانی می‌کنه رو دانلود می‌کنه؛ این الگو مشابه همون منطق Fallback در Font Stack‌ه که در درس ۸-۱ دیدیم.

فرمت‌های رایج فونت

فرمت پسوند فایل وضعیت
WOFF2 .woff2 فشرده‌ترین و مدرن‌ترین فرمت؛ باید همیشه اولین گزینه باشد
WOFF .woff فرمت قدیمی‌تر؛ گزینه جایگزین مناسب برای پشتیبانی گسترده‌تر
TTF/OTF .ttf / .otf فرمت‌های قدیمی‌تر و حجیم‌تر؛ کمتر برای وب توصیه می‌شوند

font-weight و font-style: تعریف نسخه‌های مختلف یک فونت

@font-face {
  font-family: "Vazirmatn";
  src: url("Vazirmatn-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
}

@font-face {
  font-family: "Vazirmatn";
  src: url("Vazirmatn-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
}
p {
  font-family: "Vazirmatn";
  font-weight: 400;
}

strong {
  font-family: "Vazirmatn";
  font-weight: 700;
}

نکته مهم اینجاست: هر ضخامت (Weight) یا سبک (Style) از یک فونت، معمولاً در یک فایل کاملاً جداگانه قرار داره. با تعریف چند @font-face با همون font-family، ولی font-weight و font-style متفاوت، مرورگر خودش یاد می‌گیره که برای font-weight: 700، باید کدوم فایل دقیق رو بارگذاری کنه؛ بدون این‌که ما مجبور باشیم اسم فایل رو مستقیماً در جای دیگه‌ای مشخص کنیم.

font-display: کنترل رفتار هنگام بارگذاری

@font-face {
  font-family: "MyFont";
  src: url("myfont.woff2") format("woff2");
  font-display: swap;
}

Property به اسم font-display مشخص می‌کنه، در فاصله زمانی بین شروع بارگذاری صفحه تا تکمیل دانلود فونت سفارشی، مرورگر چه رفتاری داشته باشه.

مقدار رفتار
swap ابتدا با یک فونت جایگزین سیستمی نمایش داده می‌شود؛ به‌محض آماده شدن فونت اصلی، جایگزین می‌شود
block متن تا مدت کوتاهی نامرئی می‌ماند تا فونت اصلی آماده شود؛ در صورت تأخیر زیاد، فونت جایگزین نمایش داده می‌شود
fallback حالتی بینابین؛ زمان انتظار کوتاه‌تر از block دارد
auto رفتار پیش‌فرض مرورگر (که معمولاً مشابه block عمل می‌کند)

مقدار swap، امروزه رایج‌ترین انتخابه؛ چون تضمین می‌کنه کاربر بلافاصله یه متن قابل‌خوندن (حتی با فونت موقت) می‌بینه، به‌جای اینکه مدتی صفحه کاملاً خالی از متن باشه؛ این رفتار مستقیماً به تجربه کاربری و Performance مرتبطه که در فصل‌های آینده کامل‌تر بررسیش می‌کنیم.

Variable Fonts: یک فایل، بی‌نهایت تنوع

تا اینجا دیدیم که برای هر ضخامت متفاوت از یک فونت (مثلاً Regular و Bold)، باید یک فایل کاملاً جدا تعریف بشه. Variable Fonts (فونت‌های متغیر) این محدودیت رو کاملاً برمی‌دارن: یک فایل فونت متغیر، می‌تونه به‌جای چند نسخه ثابت، طیف کاملی از ضخامت‌ها (و گاهی حتی کشیدگی یا سایر ویژگی‌ها) رو در خودش جای بده.

@font-face {
  font-family: "InterVariable";
  src: url("Inter-Variable.woff2") format("woff2-variations");
  font-weight: 100 900;
}

نکته مهم این مثال: به‌جای یک عدد ثابت (مثل font-weight: 400;)، یک بازه (100 900) تعریف شده. این یعنی این فایل فونت به‌تنهایی، تمام ضخامت‌های بین ۱۰۰ (خیلی نازک) تا ۹۰۰ (خیلی ضخیم) رو پشتیبانی می‌کنه؛ نه فقط چند مقدار ثابت خاص.

استفاده از دقت کامل در Variable Fonts

h1 {
  font-family: "InterVariable";
  font-weight: 550;
}

حالا با داشتن این فونت متغیر، می‌شه از هر عدد دلخواهی بین ۱۰۰ تا ۹۰۰ استفاده کرد (مثلاً 550، که در فونت‌های معمولی و ثابت اصلاً معنایی نداشت، چون فقط مقادیر گسسته مثل ۴۰۰ یا ۷۰۰ در دسترس بودن)؛ مرورگر خودش، دقیقاً همون ضخامت درخواستی رو از داخل یک فایل واحد محاسبه و رندر می‌کنه.

مزیت‌های اصلی Variable Fonts

  • حجم کمتر کلی: به‌جای دانلود چند فایل جداگانه (مثلاً Regular، Bold، Italic، Bold-Italic)، فقط یک فایل واحد (که معمولاً کوچک‌تر از مجموع همه اون فایل‌های جدا هست) دانلود می‌شه.
  • دقت کامل: امکان استفاده از هر عدد دلخواه در بازه پشتیبانی‌شده، نه فقط چند مقدار ثابت از پیش تعریف‌شده.
  • امکان انیمیشن‌سازی ضخامت: چون ضخامت حالا یک عدد پیوسته‌ست، می‌شه حتی با Transition، به‌آرومی از یک ضخامت به ضخامت دیگه انیمیت کرد؛ چیزی که با فونت‌های ثابت اصلاً ممکن نبود.

وضعیت پشتیبانی مرورگرها

Variable Fonts امروزه در تمام مرورگرهای مدرن پشتیبانی می‌شن، ولی همچنان پیش از استفاده گسترده در یک پروژه واقعی، بررسی وضعیت پشتیبانی مرورگرهای هدف پروژه توصیه می‌شه؛ مخصوصاً اگه پروژه نیاز به سازگاری با مرورگرهای قدیمی‌تر داشته باشه.

یک مثال کامل و ترکیبی

@font-face {
  font-family: "AppFont";
  src: url("AppFont-Variable.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-display: swap;
}

body {
  font-family: "AppFont", sans-serif;
  font-weight: 400;
}

h1 {
  font-weight: 750;
}

.subtle-text {
  font-weight: 300;
}

در این مثال، فقط با یک فایل فونت واحد، سه ضخامت کاملاً متفاوت (۴۰۰، ۷۵۰ و ۳۰۰) برای بخش‌های مختلف صفحه تعریف شده؛ بدون نیاز به دانلود چند فایل جداگانه.

نکات مهم

  • @font-face اسم دلخواه یک فونت را به یک یا چند فایل واقعی متصل می‌کند.
  • هر ضخامت یا سبک از یک فونت ثابت (غیر متغیر)، معمولاً نیازمند یک @font-face جداگانه است.
  • Variable Fonts با تعریف یک بازه برای font-weight، امکان استفاده از هر عدد دلخواه در آن بازه را، از داخل یک فایل واحد، فراهم می‌کنند.

اشتباهات رایج

  • فراموش کردن font-display: swap، که می‌تواند باعث نامرئی ماندن طولانی متن در حین بارگذاری فونت شود.
  • تعریف چند @font-face جداگانه برای هر ضخامت، در حالی که استفاده از یک Variable Font واحد می‌توانست حجم کلی را کاهش دهد.
  • استفاده از یک عدد font-weight خارج از بازه پشتیبانی‌شده توسط فایل فونت متغیر.

جمع‌بندی

قانون @font-face امکان معرفی یک فونت سفارشی، از طریق اتصال یک نام دلخواه به یک یا چند فایل واقعی، فراهم می‌کند و Propertyهایی مثل font-weight، font-style و font-display رفتار دقیق این بارگذاری را کنترل می‌کنند. Variable Fonts، به‌عنوان یک فناوری مدرن‌تر، این مفهوم را با تعریف یک بازه (به‌جای یک مقدار ثابت) گسترش می‌دهند و امکان استفاده از هر ضخامت دلخواه، از داخل تنها یک فایل فونت، با حجم کلی کمتر، فراهم می‌کنند.