جاوااسکریپت | JavaScript
527 subscribers
704 photos
158 videos
4 files
566 links
کانال @IR_javascript حاوی اطلاعات مفید در حوزه برنامه نویس فرانت که بصورت روزانه بروز می‌شود.
در این کانال شما به:
[1] مطالب تازه
[2] تحلیل‌های عمیق
[3] نکات آموزشی
[4] چالش
[5] ابزار و راهنمایی‌های کاربردی
دسترسی خواهید داشت.

🆔@IR_javascript
Download Telegram
ویدیو دوبله شده در مورد اسولت نسخهٔ پنج (The Complete Svelte 5 Course) [+لینک]

اسولت یک فریم‌ورک همراه با کامپایلر اختصاصی است که هدفش تولید کد کلاینتی فوق‌العاده سبک است؛ و البته فریم‌ورکی نسبتاً پرطرفدار نیز به شمار می‌آید.

«ماتیا از کرواسی» (امضایی که خودِ نویسنده استفاده می‌کند) دوره‌ای بسیار جامع گرد آورده که به شما امکان می‌دهد اسولت نسخهٔ پنج را از پایه بیاموزید. این دوره شامل بیست و هشت فصل، سه ساعت ویدئو و تعداد زیادی دمو است. دوره رایگان است،
کد ها در لینک زیر موحود است
https://joyofcode.xyz/learn-svelte

🔗https://www.aparat.com/v/dbp98sl
#️⃣#tip #dub
👥@IR_javascript_group
🆔@IR_javascript
👍1
اگر صفحهٔ خطا از حداقل اندازهٔ مشخصی کوتاه‌تر باشد (معمولاً پانصد و دوازده بایت)، مرورگر آن را پنهان می‌کند و صفحهٔ خطای پیش‌فرض خودش را نمایش می‌دهد؛ همان پیام معروف «این صفحه قابل نمایش نیست».
این مشکل حدود پانزده سال پیش هم مطرح شده است، بدون هیچ پیشرفتی
در واقع، این پُر کردن صفحه با کامنت‌ها را خودِ سرور اِن‌جین‌اِکس انجام می‌دهد.


#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
1
👏 <template> و <slot>

قهرمانان فراموش‌شدهٔ فرانت‌اند که شایستهٔ توجه هستند

همهٔ ما فریم‌ورک‌ها را می‌شناسیم و دوست داریم، اما باید قبول کنیم که مرورگرها می‌توانند کارهای بسیار بیشتری انجام دهند. دو عنصر که اغلب نادیده گرفته می‌شوند اما می‌توانند زندگی توسعه‌دهندگان را بسیار ساده‌تر کنند، <template> و <slot> هستند. این عناصر امکان ساخت «مینی‌کامپوننت‌ها» را مستقیماً در مرورگر فراهم می‌کنند، بدون نیاز به React، Vue یا Svelte.

❗️ <template>

عنصر <template> برای ذخیرهٔ بخش‌هایی از کد HTML استفاده می‌شود که تا زمانی که با جاوااسکریپت به صورت دستی درج نشوند، در صفحه نمایش داده نمی‌شوند. این ابزار ایده‌آل برای ایجاد بلوک‌های تکرارشوندهٔ HTML است.

<template id="card">
<div class="card">
<h3 class="title"></h3>
<p class="text"></p>
</div>
</template>

<script>
const tpl = document.querySelector('#card');
const clone = tpl.content.cloneNode(true);
clone.querySelector('.title').textContent = 'Hello';
document.body.appendChild(clone);
</script>


❗️ <slot>

عنصر <slot> درون کامپوننت‌های سفارشی برای درج HTML خارجی استفاده می‌شود، که اجازه می‌دهد کامپوننت‌های رابط کاربری کامل بدون فریم‌ورک‌های خارجی ایجاد شوند. این روش هم معنایی و دسترس‌پذیر است و هم سفارشی‌سازی کامپوننت‌ها را ساده می‌کند.

<my-button>
<span>Click me</span>
</my-button>

<script>
class MyButton extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<button class="btn">
<slot></slot>
</button>
`;
}
}
customElements.define('my-button', MyButton);
</script>


📌 مرورگرها اکنون آن‌قدر هوشمند شده‌اند که حتی فریم‌ورک‌های پیچیده هم لازم نیستند! همهٔ این‌ها به لطف Web Components، Islands، Partial Hydration و SSR امکان‌پذیر است. و استفاده از این دو عنصر <template> و <slot> باعث می‌شود بسیاری از مسائل که قبلاً تنها با فریم‌ورک‌های کوچک حل می‌شدند، حالا بدون بار اضافی و پیچیدگی قابل مدیریت باشند.

#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
2
ویژگی‌های منطقی در CSS — چگونه استایل‌ها را منعطف و جهانی کنیم

همیشه به حاشیه‌ها از بالا، راست، پایین و چپ فکر می‌کنیم. اما در دنیایی که جهت متن می‌تواند تغییر کند، این روش محدودکننده می‌شود. اینجا logical properties به کمک می‌آیند. آن‌ها اجازه می‌دهند حاشیه‌ها و اندازه‌ها را بر اساس جریان متن تعیین کنید، نه بر اساس سمت‌ها.

ℹ️ logical properties چیست و چه کاربردی دارند؟

inline جهت متن را مشخص می‌کند (مثلاً از چپ به راست یا راست به چپ)

block جهت بلوک‌ها را تعیین می‌کند، معمولاً از بالا به پایین، بسته به جریان سند

برای حاشیه‌های افقی از margin-inline-start و margin-inline-end استفاده می‌شود

برای حاشیه‌های عمودی از padding-block-start و padding-block-end

برای موقعیت و مرزها از border-inline و inset-block استفاده می‌شود

مزایا و کاربردها:

بین‌المللی‌سازی
در محصولاتی که چند زبان پشتیبانی می‌کنند، logical properties باعث صرفه‌جویی در زمان تنظیم استایل‌ها می‌شود.

طرح‌های قابل تغییر جهت
برای کامپوننت‌هایی که ممکن است «برگردانده» شوند (مثل آواتار سمت چپ/راست یا سایدبار)، logical properties نیاز به شرط‌نویسی در CSS را حذف می‌کند.

/* روش قدیمی */
.card {
padding-top: 12px;
padding-left: 16px;
}

/* با ویژگی‌های منطقی */
.card {
padding-block-start: 12px;
padding-inline-start: 16px;
}

/* خلاصهٔ کوتاه:
margin-inline — حاشیه‌های افقی
margin-block — حاشیه‌های عمودی
padding-inline — فاصله داخلی افقی
padding-block — فاصله داخلی عمودی
inset-inline — موقعیت افقی (چپ/راست)
inset-block — موقعیت عمودی (بالا/پایین) */




#️⃣#tip #css
👥@IR_javascript_group
🆔@IR_javascript
📸 ویژگی‌های loading`، `decoding و fetchpriority — چگونه با ویژگی‌های بومی، بارگذاری تصاویر را سریع‌تر کنیم

سه ویژگی ساده و بومی HTML وجود دارند که می‌توانند بارگذاری تصاویر را بسیار سریع‌تر کرده و رابط کاربری شما را پاسخگوتر کنند. اگرچه تمام مرورگرهای مدرن از آن‌ها پشتیبانی می‌کنند، اما در عمل به ندرت استفاده می‌شوند. در ادامه هر یک را بررسی می‌کنیم:

⬅️ `loading="lazy"` — بارگذاری تنبل

ویژگی loading="lazy" باعث می‌شود مرورگر بارگذاری تصاویر خارج از دید کاربر را به تعویق بیندازد. این کار ترافیک کاربر را کاهش می‌دهد، زمان تا تعامل کامل (TTI) را کم می‌کند و فشار روی دستگاه‌های ضعیف را کاهش می‌دهد. از این ویژگی برای تمام تصاویر زیر اولین صفحه، کارت‌ها، فهرست‌ها و گالری‌ها استفاده کنید.
⚠️ اما برای تصاویر مهم در بالای صفحه، مانند لوگو یا تصاویر Hero، از این ویژگی استفاده نکنید تا از تأخیر در بارگذاری جلوگیری شود.

⚡️ `decoding="async"` — رمزگشایی غیرهمزمان

ویژگی async به مرورگر اجازه می‌دهد تصاویر را به صورت غیرهمزمان رمزگشایی کند**، بدون اینکه رندر سایر عناصر را متوقف کند. این کار باعث کاهش تأخیرهای بصری و افزایش سرعت بارگذاری صفحات می‌شود. به‌ویژه برای تصاویر بزرگ و عناصر در فیدها یا لیست‌ها مفید است و تجربهٔ کاربری روان‌تر را فراهم می‌کند.

🔫
fetchpriority="high | low" — مدیریت اولویت بارگذاری**

این ویژگی تعیین می‌کند که تصویر با چه اولویتی بارگذاری شود: high برای بارگذاری فوری و low برای بارگذاری با تأخیر. استفاده از آن باعث کاهش رقابت منابع، افزایش سرعت LCP و کاهش تأخیرهای بصری در رندر صفحه می‌شود.

👀 نمونه‌ها و نحوهٔ استفادهٔ ترکیبی

<!-- بارگذاری تنبل -->
<img src="hero.png" loading="lazy" />

<!-- رمزگشایی غیرهمزمان -->
<img src="photo.jpg" decoding="async" />

<!-- مدیریت اولویت بارگذاری -->
<img src="hero.jpg" fetchpriority="high" />
<img src="avatar.jpg" loading="lazy" fetchpriority="low" />

<!-- ترکیب همه ویژگی‌ها -->
<img src="hero.jpg" decoding="async" fetchpriority="high" />
<img src="thumb.jpg" loading="lazy" decoding="async" fetchpriority="low" />


استفاده از این سه ویژگی به‌صورت هوشمندانه می‌تواند سرعت بارگذاری تصاویر و تجربهٔ کاربری سایت شما را به طور قابل توجهی بهبود دهد.


#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
👍2
📣 همگام‌سازی وضعیت بین تب‌ها: BroadcastChannel، SharedWorker و localStorage

وقتی کاربر چند تب از یک اپلیکیشن را باز می‌کند، اغلب مشکل همگام‌سازی وضعیت پیش می‌آید. مثلاً کاربر در یک تب از حساب کاربری خارج می‌شود، اما در تب‌های دیگر اپلیکیشن همچنان او را وارد شده فرض می‌کند. در سال ۲۰۲۵ چند ابزار برای حل این مسئله داریم: BroadcastChannel**، **SharedWorker و برای مرورگرهای قدیمی، localStorage.

---

BroadcastChannel — راه‌حل ساده برای همگام‌سازی پیام‌ها

این API امکان ارسال و دریافت پیام‌ها بین تب‌ها را به صورت همزمان فراهم می‌کند. مناسب برای:

* اطلاع‌رسانی ورود/خروج
* انتخاب تم
* به‌روزرسانی کش
* اطلاع از نسخهٔ جدید اپلیکیشن

مزایا: ساده، سریع، کار در پس‌زمینه
محدودیت‌ها: وضعیت مشترک پیچیده را پشتیبانی نمی‌کند

// BroadcastChannel
const channel = new BroadcastChannel("session");

channel.onmessage = (e) => {
console.log("message:", e.data);
};

channel.postMessage({ loggedOut: true });


---

SharedWorker — وقتی همه تب‌ها مثل یک اپلیکیشن عمل می‌کنند

ابزاری برای کار متمرکز بین تب‌ها که امکان همگام‌سازی وضعیت، کشینگ و مدیریت درخواست‌ها را فراهم می‌کند. مناسب برای اپلیکیشن‌هایی که نیاز به هماهنگی بین تب‌ها دارند.

مزایا: ذخیرهٔ مرکزی وضعیت، اشتراک منابع، کاهش درخواست‌های تکراری API
محدودیت‌ها: در Safari پشتیبانی نمی‌شود، دیباگ پیچیده و نیاز به معماری حساب‌شده دارد

// main.js
const worker = new SharedWorker("worker.js");
worker.port.postMessage({ type: "ping" });
worker.port.onmessage = (e) => console.log(e.data);

// worker.js
onconnect = (e) => {
const port = e.ports[0];
port.onmessage = () => port.postMessage("pong");
};


---

LocalStorage + storage event — روش قدیمی ولی کارآمد

یکی از ساده‌ترین روش‌های همگام‌سازی داده‌ها، مناسب برای:

* مرورگرهای قدیمی
* پروژه‌هایی بدون ServiceWorker یا SharedWorker
* سناریوهای سادهٔ همگام‌سازی تب‌ها

مزایا: پیاده‌سازی ساده، سازگاری بالا
محدودیت‌ها: فقط رشته‌ها ذخیره می‌شوند، رویداد storage در تب تغییر دهنده رخ نمی‌دهد و ممکن است کندتر از BroadcastChannel باشد

// LocalStorage + storage event
window.addEventListener("storage", (e) => {
if (e.key === "logout") {
// همگام‌سازی وضعیت
}
});


---

📌 جمع‌بندی:

* برای اعلان‌ها و رویدادهای ورود/خروج → BroadcastChannel
* برای اشتراک وضعیت در PWA و داشبوردها → SharedWorker
* برای مرورگرهای قدیمی → localStorage + storage event

هر ابزار ویژگی‌های خاص خود را دارد و انتخاب آن بستگی به پیچیدگی پروژه، مرورگرهای هدف و نوع داده‌ها دارد.


#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
👍1
Media is too big
VIEW IN TELEGRAM
کش کردن ETag در HTTP یک مکانیزم برای اعتبارسنجی کش وب است.
در این ویدئو، خواهیم آموخت که ETag‌ها چه هستند و چگونه با هدرهای If-None-Match و If-Match و کدهای وضعیت HTTP ۳۰۴ و ۴۱۲ مرتبط می‌شوند.


🔗https://www.youtube.com/watch?v=tWu9lBlghOc
#️⃣#tip #dub
👥@IR_javascript_group
🆔@IR_javascript
🎭 چگونه یک API فرانت‌اند بدون دردسر بنویسیم

هنگام توسعهٔ API فرانت‌اند، مهم است که به یاد داشته باشیم این فقط یک لایهٔ نازک روی بک‌اند نیست. این یک قرارداد کامل است که مشخص می‌کند محصول چقدر کاربرپسند خواهد بود، تیم چگونه آن را درک می‌کند و چه مشکلاتی در آینده ممکن است رخ دهد. در ادامه یک چک‌لیست برای ساخت API ارائه می‌شود که نه‌تنها کار می‌کند، بلکه به‌راحتی قابل نگهداری است.

⬆️ پیش‌بینی‌پذیری API

یکی از بزرگ‌ترین مشکلات، عدم انسجام است. نام‌های متفاوت فیلدها، ساختارهای مختلف پاسخ یا کدهای خطا می‌توانند هر تلاش برای کار پایدار با API را خراب کنند. اگر توسعه‌دهنده با یکی از اندپوینت‌های شما کار کرده باشد، باید اطمینان داشته باشد که اندپوینت بعدی تقریباً مشابه خواهد بود. این موضوع به جلوگیری از مشکلات نگهداری و پیاده‌سازی سریع ویژگی‌های جدید کمک می‌کند.

⬆️ مستندسازی خودکار

مستندسازی دستی به‌سرعت منسوخ می‌شود. از ابزارهایی استفاده کنید که مستندسازی را به‌صورت خودکار تولید کنند. از OpenAPI یا Swagger، JSON Schema و تولید خودکار تایپ‌های TypeScript و کلاینت استفاده کنید. با این روش، API و مستندات همیشه به‌روز خواهند بود و فرانت‌اند پایدارتر خواهد شد.

⬆️ ثبات نوع داده‌ها

مشکلات زمانی آغاز می‌شوند که فیلدهای داده‌ای هم می‌توانند null باشند و هم ممکن است اصلاً وجود نداشته باشند. این موضوع رابط کاربری را خراب کرده و اپلیکیشن را ناپایدار می‌کند. برای مثال، بهتر است همیشه ساختار یکسانی با مقادیر صحیح داشته باشیم تا فیلدهای تصادفی با انواع دادهٔ متفاوت. اطمینان حاصل کنید که داده‌ها همیشه پایدار و پیش‌بینی‌پذیر باشند.

⬆️ از «مقدارهای جادویی» پرهیز کنید

نمونهٔ بد یک API: { "status": 3 }. این مقدار چه معنایی دارد؟ این قابل خواندن نیست. بهتر است از مقادیر قابل فهم استفاده کنید، مثل { "status": "blocked" }. این کار تعداد خطاها را کاهش می‌دهد، نگهداری و خواندن API را آسان‌تر می‌کند و فهم توسعه‌دهندگان را افزایش می‌دهد.

⬆️ خطاها فقط کد وضعیت نیستند

خطاها باید با دقت مدیریت شوند. کدهای خطای پایه مانند ۲۰۰ و ۵۰۰ برای عملکرد خوب کافی نیستند. به جای آن از کدهای خطای واضح همراه با توضیح استفاده کنید. برای مثال، اگر جلسه منقضی شده باشد، پاسخ دهید:

{
"error": {
"code": "INVALID_TOKEN",
"message": "Token expired"
}
}


این کار به بازیابی مؤثر جلسات، retry و بهبود تجربهٔ کاربری کمک می‌کند.

⬆️ هنگام نوشتن API به نیازهای فرانت‌اند توجه کنید:

• کاهش تعداد درخواست‌های کوچک
• قابلیت کش کردن
• داده‌های نرمال‌شده
• پاسخ‌های فشرده

فرانت‌اند دوست ندارد API پاسخ‌های حجیم با داده‌های اضافی بازگرداند. به صفحه‌بندی، batch کردن و ETag‌های پایدار برای منابع توجه کنید.

⬆️ همه چیز مورد نیاز برای کش کردن را فراهم کنید

‏API باید از کش پشتیبانی کند. از مکانیزم‌هایی مانند ETag**، **Cache-Control**، **Last-Modified و max-age استفاده کنید. این امکان را به فرانت‌اند می‌دهد که کش را به‌صورت مؤثر استفاده کرده، بار را کاهش دهد و سرعت را افزایش دهد.

⬆️ از over-fetching و under-fetching محافظت کنید

اطمینان حاصل کنید که API داده‌های اضافی (over-fetching) ارسال نمی‌کند، مثل زمانی که نیازی به نقش‌ها یا تنظیمات کاربران نیست. همچنین فرانت‌اند را مجبور نکنید چندین درخواست برای دریافت داده‌های مورد نیاز ارسال کند (under-fetching). از view model‌هایی استفاده کنید که برای صفحات خاص UI طراحی شده‌اند.

⬆️ نسخه‌بندی API را با دقت انجام دهید

نسخه‌بندی API باید هدفمند باشد. مسیر ساده با شماره نسخه‌ها مانند /v2 یا /v3 کافی نیست. اطمینان حاصل کنید که هر نسخه داخلی سازگار است و امکان بازگشت فراهم باشد. نسخه‌بندی باید پیش‌بینی‌پذیر و واضح باشد.

⬆️ یک لایۀ کلاینت ایجاد کنید

فرانت‌اند باید بتواند کارهایی مانند retry، لغو درخواست‌ها، debounce، timeout و مدیریت توکن را به‌صورت مستقل انجام دهد. این‌ها نباید مسئولیت بک‌اند باشند. یک لایۀ واحد API برای کلاینت با استفاده از custom fetch wrapper، axios instance یا TanStack Query ایجاد کنید. یک کلاس واحد برای همهٔ درخواست‌ها، رفتار پایدارتر و کنترل بهتر روی درخواست‌ها را تضمین می‌کند.

📌 یک API فرانت‌اند عالی فقط مجموعه‌ای از نقاط ورود نیست، بلکه یک سیستم کامل است که باید پیش‌بینی‌پذیر و پایدار باشد. بیایید APIهایی بسازیم که فرانت‌اند را خراب نکند و زندگی کل تیم را ساده‌تر کند.

#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
2
Cumulative Layout Shift:
متریکی است که نشان می‌دهد عناصر صفحه پس از اولین رندر، با چه فرکانسی و تا چه حد به‌صورت غیرمنتظره جابه‌جا می‌شوند. مرورگر برای هر جابه‌جایی محاسبه می‌کند چه بخشی از صفحه تحت تأثیر قرار گرفته و عناصر چه مسافتی حرکت کرده‌اند، سپس این مقادیر را با هم جمع می‌زند. در نتیجه، CLS نه سرعت بارگذاری، بلکه پایداری رابط کاربری در طول زمان را اندازه‌گیری می‌کند.

📚 از کجا می‌آید؟
اگر در لحظهٔ اولین محاسبهٔ layout، مرورگر نداند یک عنصر چه فضایی را اشغال خواهد کرد، برای آن فضایی رزرو نمی‌کند. وقتی آن عنصر ظاهر می‌شود یا اندازه‌اش تغییر می‌کند، مرورگر مجبور است چیدمان صفحه را دوباره محاسبه کند و کاربر نتیجه را به‌صورت یک «پرش» می‌بیند.
تصاویر: اصلی‌ترین و ساده‌ترین مورد
وقتی یک <img> بدون ابعاد از پیش تعیین‌شده بارگذاری می‌شود، مرورگر نمی‌تواند ارتفاع آن را محاسبه کند. وقتی تصویر ظاهر می‌شود، تمام محتوای زیر آن تغییر مکان می‌دهد.
راه حل: از قبل به مرورگر اطلاع دهید - عرض و ارتفاع واقعی را مشخص کنید.
آنها اندازه ذاتی (n نسبت ابعاد) را تنظیم می‌کنند
<img
src="/img/hero.jpg"
width="1200"
height="675"
alt=""
/>

همه تصاویر در تگ‌های <img> قرار نمی‌گیرند. تصاویر پس‌زمینه، کارت‌ها و اجزای پویا اغلب از طریق CSS یا جاوا اسکریپت می‌آیند. در این موارد، عرض، ارتفاع و سایر ویژگی‌ها نقش دارند.
نسبت ابعاد را در نظر می‌گیرد.
.media {
}
aspect-ratio: 16/9;
width: 100%;


فونت‌ها: منبع نادیده گرفته شده‌ی تغییرات
حتی با تصاویر بی‌نقص، CLS می‌تواند به دلیل فونت‌ها باقی بماند. وقتی صفحه لود می‌شود:
۱. مرورگر هنوز فونت اصلی سایت را دانلود نکرده
۲. باید تصمیم بگیرد:
متن را نشان بدهد یا
صبر کند تا فونت دانلود شود؟
اگر بعداً فونت اصلی برسد و جای فونت موقت (fallback) را بگیرد، اندازه‌ی حروف و فاصله‌ی خطوط تغییر می‌کند چیدمان صفحه می‌پرد (CLS)
چه چیزهایی کمک می‌کند:
1-استفاده از swap

font-display: swap;

// متن را فوراً نشان بده
// اول با یک فونت موقت (fallback)
// وقتی فونت اصلی آمد، آن را جایگزین کن

2-استفاده از فونت‌های fallback با متریک‌های نزدیک به فونت اصلی
3-پری لود کردن فونت‌ها فقط در موارد واقعاً بحرانی و ضروری
@font-face {
font-family: MyFont;
src: url(myfont.woff2) format("woff2");
font-display: swap;
}


تبلیغات، iframe و ویجت‌ها

بلوک‌های تبلیغاتی و iframeها معمولاً به‌صورت ناهمگام بارگذاری می‌شوند و بعد از اولین رندر ظاهر می‌گردند. اگر از قبل فضایی برای آن‌ها در نظر گرفته نشده باشد، با ورودشان محتوا را به پایین «هل می‌دهند» و باعث جابه‌جایی چیدمان می‌شوند.

قاعدهٔ کاربردی بسیار ساده است:
هر بلوک خارجی یا ناهمگام باید از پیش یک اسلات مشخص داشته باشد؛
چه با ارتفاع ثابت، چه با aspect-ratio، یا با استفاده از placeholder / skeleton.


#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
‏tree-shaking در فونت‌ها

همان‌طور که فایل‌های بزرگ JavaScript به چند فایل کوچک‌تر تقسیم می‌شوند و فقط در صورت نیاز بارگذاری می‌گردند، فایل‌های فونت هم می‌توانند به زیرمجموعه‌های کوچک‌تر شکسته شوند. به این کار font subsetting یا «تقسیم فونت به زیرمجموعه‌ها» گفته می‌شود.

تعداد گلیف‌ها در یک فونت به زبان‌هایی بستگی دارد که آن فونت پشتیبانی می‌کند. بعضی فونت‌ها تقریباً تمام کاراکترهای یونیکد را در خود دارند، در حالی که فونت‌هایی که فقط زبان انگلیسی را پوشش می‌دهند، مجموعهٔ بسیار محدودتری از نمادها را شامل می‌شوند. هرچه تعداد گلیف‌ها بیشتر باشد، حجم فایل فونت هم بزرگ‌تر خواهد بود.

در سایت‌های فارسی‌زبان (و روسی‌زبان)، معمولاً فقط از حروف سیریلیک یا فارسی، اعداد و نشانه‌های اصلی نگارشی استفاده می‌شود. در زبان‌هایی مثل اوکراینی، بلاروسی و سایر زبان‌های اسلاوی، علاوه بر حروف اصلی سیریلیک، تعدادی نماد از «سیریلیک توسعه‌یافته» هم به کار می‌رود.

کاراکترهای لاتین معمولاً استفادهٔ بسیار محدودی دارند؛ چه برسد به نمادهای گروه CJK (چینی، ژاپنی، کره‌ای) یا سایر زبان‌ها. این دقیقاً همان مشکلی است که در مورد کد JavaScript استفاده‌نشده داریم و با code splitting و tree-shaking حل می‌شود. برای فونت‌ها هم می‌توان همین رویکرد را به کار گرفت.

به‌جای یک فونت بزرگ با مجموعه‌ای عظیم از نمادها، می‌توان آن را به چند فونت کوچک‌تر تقسیم کرد:

* فونت سیریلیک پایه: حروف اصلی سیریلیک، اعداد، نشانه‌های رایج نگارشی؛ می‌توان نقل‌قول‌های تایپوگرافیک، خط تیرهٔ بلند، سه‌نقطه و موارد مشابه را هم اضافه کرد؛
* فونت سیریلیک توسعه‌یافته: حروف و نمادهای خاص (علامت‌های دیاکریتیک) برای زبان‌های اوکراینی، بلاروسی، بلغاری، صربی و دیگر زبان‌ها؛
* فونت لاتین پایه: حروف اصلی الفبای لاتین؛
* فونت لاتین توسعه‌یافته: حروف و نمادهای خاص (دیاکریتیک‌ها) برای زبان‌هایی مثل آلمانی، لهستانی، لیتوانیایی، ترکی و غیره؛
* سایر زیرمجموعه‌ها در صورت نیاز.

در یک سایت فارسی یا روسی‌زبان، حروف لاتین معمولاً برای اصطلاحات، نام‌ها و ابزارهای ترجمه لازم می‌شوند. خود من سایت‌های انگلیسی‌زبان را می‌بینم و گاهی از قابلیت ترجمهٔ صفحه استفاده می‌کنم؛ خارجی‌ها هم همین کار را می‌کنند. خوشایند نیست که به‌جای فونت طراحی‌شدهٔ سایت، ناگهان Times New Roman نمایش داده شود.

---

## روش‌های تقسیم فونت

چند راه برای این کار وجود دارد. ساده‌ترین روش استفاده از Google Fonts است؛
نه به این معنا که فونت را مستقیم از آن سرویس لود کنید (که توصیه نمی‌شود)، بلکه برای گرفتن زیرمجموعه‌های آماده:

۱. فونت موردنظر را در Google Fonts پیدا می‌کنید؛
۲. لینک تولیدشده داخل <link rel="stylesheet"> را کپی می‌کنید؛
۳. لینک را در یک تب جدید باز می‌کنید؛ مجموعه‌ای از دستورهای @font-face می‌بینید؛
۴. زیرمجموعه‌های موردنیاز (که با کامنت مشخص شده‌اند) را کپی می‌کنید؛
۵. فایل‌های فونت مربوطه را از آدرس‌های src دانلود می‌کنید؛
۶. دستورهای @font-face را به پروژه اضافه کرده و لینک‌ها را به فایل‌های دانلودشده تغییر می‌دهید.

روش دیگر استفاده از ابزار آنلاین Font Subsetting است. در این روش، فونت را آپلود می‌کنید، نمادها یا بازه‌های یونیکد موردنظر را مشخص می‌کنید و خروجیِ فونتی را می‌گیرید که فقط شامل همان کاراکترهاست.

روش سوم استفاده از ابزار خط فرمان glyphhanger است که جزئیات آن در مقالهٔ زک لِدِرمن توضیح داده شده است. (https://www.zachleat.com/web/glyphhanger/)

---

## نقش unicode-range

برای اینکه مرورگر بداند چه زمانی و کدام زیرمجموعهٔ فونت را بارگذاری کند، باید بداند هر فونت شامل چه کاراکترهایی است. این اطلاعات با ویژگی unicode-range در دستور @font-face مشخص می‌شود:

/* cyrillic */
@font-face {
/* ... */
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}


ویژگی unicode-range فهرستی از کاراکترها را در قالب یونیکد مشخص می‌کند. می‌توان:

* یک نماد مشخص را تعیین کرد (مثلاً U+2116 که همان علامت شماره «№» است)،
* یا یک بازه را مشخص نمود (مثلاً U+0410-044F از حرف «А» تا «я»).

فهرست کامل مقادیر یونیکد را می‌توان در جدول‌های یونیکد مشاهده کرد.

هنگام بارگذاری صفحه، مرورگر تمام کاراکترهای موجود را بررسی می‌کند. اگر حتی یک کاراکتر از عناصر استفاده‌کنندهٔ فونت، داخل بازهٔ unicode-range باشد، آن فونت دانلود می‌شود. اگر هیچ‌کدام از کاراکترهای صفحه در آن بازه نباشند، فونت اصلاً بارگذاری نخواهد شد.


#️⃣#tip #css
👥@IR_javascript_group
🆔@IR_javascript