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

🆔@IR_javascript
Download Telegram
چطور محتوای «پنهان، اما قابل‌جست‌وجو» بسازیم؟ 🔍

تصور کنید یک صفحهٔ طولانی با بخش پرسش‌های متداول، آکاردئون‌ها و قسمت‌های جمع‌شونده دارید. کاربر Ctrl/Cmd+F را می‌زند، یک کلمه وارد می‌کند و... مرورگر هیچ چیزی نشان نمی‌دهد، چون متن موردنظر داخل یک آکاردئون بسته پنهان شده است. آزاردهنده است، نه؟ 😔

برای چنین موقعیت‌هایی، ویژگی hidden="until-found" وجود دارد — یک صفت که اجازه می‌دهد محتوا از نظر بصری مخفی باشد، اما همچنان برای جست‌وجو در صفحه قابل‌دسترسی بماند. اگر مرورگر تطابقی پیدا کند، به‌صورت خودکار بخش مربوطه را باز می‌کند و امکان هماهنگ‌سازی رابط کاربری از طریق رویداد beforematch را فراهم می‌سازد.

در اصل، این یک بهبود تدریجی است:

✔️ اگر مرورگر از این قابلیت پشتیبانی کند → جست‌وجو به‌صورت «جادویی» عمل می‌کند؛
✔️ اگر پشتیبانی نکند → رابط کاربری همچنان کاملاً قابل استفاده باقی می‌ماند.

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

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

if (!('onbeforematch' in document)) {
// منطق جایگزین (fallback)
}


‼️ نکاتی که باید به خاطر داشت

⏺️ استفاده از beforematch برای هماهنگ کردن آکاردئون و اسکرول به محل پیدا شده بسیار کاربردی است؛

⏺️ hidden="until-found" همان display: none نیست: رفتار APIهای مربوط به چیدمان (مثل getBoundingClientRect، content-visibility، contain) ممکن است متفاوت باشد، پس بهتر است حتماً تست شود؛

⏺️ همهٔ مرورگرها از این قابلیت پشتیبانی نمی‌کنند، بنابراین برای مرورگرهای بدون پشتیبانی باید از قبل یک fallback در نظر گرفت: باز کردن صریح بخش‌های مهم یا ارائهٔ جست‌وجوی جایگزین. 😁


🔗https://codepen.io/web-dot-dev/pen/Rwxveab
🔗https://developer.chrome.com/docs/css-ui/hidden-until-found
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
انسجام و پیوستگی: چگونه کدی بنویسیم که از تغییر دادنش نترسیم 🧩

پروژه را مثل یک خانه تصور کنید. اتاق‌ها همان ماژول‌ها و کامپوننت‌ها هستند. در یک خانهٔ خوب، هر اتاق کاربرد مشخصی دارد: آشپزخانه برای آشپزی، اتاق خواب برای استراحت، حمام برای بهداشت. اما اگر در یک اتاق هم اجاق باشد، هم تخت، هم ماشین لباس‌شویی، زندگی سخت و آشفته می‌شود — این یعنی انسجام پایین: اجزای داخل یک ماژول مشغول کارهای متفاوتی هستند. 😏

درها و راهروها همان رابط‌ها و APIهایی هستند که ماژول‌ها را به هم وصل می‌کنند. درهای خوب ساده و قابل پیش‌بینی‌اند: می‌توانید محتوای یک اتاق را تغییر دهید بدون اینکه بقیهٔ خانه تحت تأثیر قرار بگیرد. اما درهای بد یعنی نبودِ مرزهای درست، جایی که مجبور می‌شوید «از دیوار رد شوید»: هر تغییر، زنجیره‌ای از اصلاحات را به دنبال می‌آورد. این همان پیوستگی بالا است.

خانهٔ ایده‌آل یعنی اتاق‌های مشخص و درهای مرتب. در کدنویسی هم یعنی: هر ماژول یک وظیفه انجام دهد و تا حد ممکن دربارهٔ بقیهٔ سیستم کم بداند. چنین کدی راحت‌تر تست می‌شود، آسان‌تر تغییر می‌کند و بهتر رشد می‌کند.

☑️ به خاطر بسپاریم:

انسجام (Cohesion) — یعنی اینکه اجزای داخل یک ماژول/کلاس/سرویس چقدر روی یک هدف مشترک متمرکز هستند.
انسجام بالا = ماژول یک کار مشخص انجام می‌دهد و آن را خوب انجام می‌دهد.

پیوستگی (Coupling) — یعنی اینکه یک ماژول چقدر به دیگر ماژول‌ها وابسته است.
پیوستگی پایین = می‌توان یک ماژول را تغییر داد بدون اینکه کل سیستم دچار موج اصلاحات شود.

ایده‌آل: انسجام بالا + پیوستگی پایین.

🧩 مزیت اصلی چیست؟

☑️ نگهداری کد ارزان‌تر و سریع‌تر می‌شود؛
☑️ تغییرات محدود و موضعی می‌مانند — با اثرات جانبی کمتر؛
☑️ معماری انعطاف‌پذیر باقی می‌ماند: می‌توان پیاده‌سازی‌ها را عوض کرد بدون اینکه سیستم بشکند؛
☑️ و البته تست کردن ساده‌تر است — ماژولی که فقط یک مسئولیت دارد، راحت‌تر موک می‌شود و پوشش تست بهتری می‌گیرد.

یک مثال کوچک در تصویر بالا 👆

و البته، معماری خوب یک ایدئولوژی نیست، بلکه یک ابزار است: زمان را ذخیره می‌کند، نگهداری را ساده‌تر می‌کند و تغییرات را امن‌تر. اما همیشه ممکن است استثناهایی وجود داشته باشد: گاهی لازم است برای یک راه‌حل فوری یا یک نمونهٔ اولیه، کمی از پاکیزگی کد صرف‌نظر کنیم. مهم این است که این مصالحه‌ها آگاهانه و موقتی باشند، نه اینکه تبدیل به عادت شوند. 😊


#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
جاوااسکریپت | JavaScript
Video
امروزه استفاده از position: sticky کاملاً رایج و معمول شده است.

اما تصور کنید اگر می‌توانستید به عناصر چسبنده به والد دسترسی پیدا کنید و با آن‌ها افکت‌ها و رفتارهای جالب ایجاد کنید، چه؟

خبر خوب اینکه این امکان اکنون وجود دارد! اخیراً قابلیت اسکرول-کوئری‌ها به عنوان بخشی از کانتینر-کوئری‌ها معرفی شده است. همان‌طور که از نامشان پیداست: [Container scroll-state queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_conditional_rules/Container_scroll-state_queries).

مثلاً می‌خواهید یک تصویر در تصویر (PIP) بسازید، به‌طوری که خواندن مقاله متوقف نشود؟

یا برعکس، تبلیغات در صفحه قطع نشود؟ :)

کاملاً امکان‌پذیر است: [نمونه عملی در CodePen](https://codepen.io/alinaki/pen/WbvMOPB)

@container scroll-state(stuck: top) {
.pip {
width: 200px;
transform: translate(-50%, 0%)
translate(calc(50vw - (50% + 1rem)), calc(100vh - (100% + 1rem)));
}
}


نکته جالب اینکه می‌توان چند translate را با هم ترکیب کرد تا نتایج ریاضیاتی و حرکتی جالبی ایجاد شود.

برای مرورگرهایی که هنوز از اسکرول-کوئری‌ها پشتیبانی نمی‌کنند، می‌توانید همیشه از یک IntersectionObserver استفاده کنید (که در نمونه نیز وجود دارد).


#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
👍1
This media is not supported in your browser
VIEW IN TELEGRAM
🖤 سالروز وفات حضرت خدیجه کبری (س)

⚫️ رسول الله صلی الله علیه و آله:
◎ خدا زنی بهتر از خدیجه به من نداد. هنگامی که مردم تکذیبم می‌کردند، او مرا تصدیق کرد و هنگامی که مردم مرا تحریم کردند، با ثروتش کمکم کرد. و خدا از او فرزندانی به من داد در حالی که از دیگر زنانم به من فرزندی نداد.

#️⃣#event
👥@IR_javascript_group
🆔@IR_javascript
10👎5
ریپازیتوری‌های مونو (Monorepo) ویژگی ناخوشایندی دارند: به مرور زمان رشد می‌کنند—و ... .

با گذشت زمان، ساختار فایل‌ها دیگر چندان گویا نیست: تعداد پوشه‌ها زیاد است، عمق تو در توی پوشه‌ها زیاد است و تشخیص اینکه کدام بخش کد زنده است و کدام غیرفعال، دشوار می‌شود.

‏Git Truck این مشکل را با بصری‌سازی ریپازیتوری حل می‌کند. این ابزار یک «نقشه» تعاملی از پروژه بر اساس تاریخچه Git می‌سازد: اندازه فایل‌ها و پوشه‌ها، فعالیت تغییرات، سهم هر نویسنده و همچنین نحوه تغییر ساختار در طول زمان، همگی قابل مشاهده هستند.

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

🔗 https://github.com/standardgalactic/git-truck
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
This media is not supported in your browser
VIEW IN TELEGRAM
اگر شما هم به استفاده از pointer-events: none روی عناصر علاقه‌مند شده‌اید — شاید برای جلوگیری از کپی شدن یا بهبود UX — احتمالاً دیباگ کردن این عناصر در DevTools می‌تواند تبدیل به کابوس شود.

خب، چطور عنصری که به رویدادهای ماوس پاسخ نمی‌دهد را انتخاب کنیم؟

همه چیز ساده است: کلید Shift را نگه داشته و انتخاب کنید. ([راهنما](https://devtoolstips.org/tips/en/select-pointer-events-none-elements/))
این روش در Chrome، Edge و Firefox کار می‌کند.


#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
متوجه شدیم که فایل‌های ignore تنها به .gitignore محدود نمی‌شوند. تقریباً هر ابزار در اکوسیستم خود نسخه‌ای از این فرمت را دارد و اگرچه اغلب گفته می‌شود «سینتکس .gitignore پشتیبانی می‌شود»، جزئیات معمولاً متفاوت است ([https://nesbitt.io/2026/02/12/the-many-flavors-of-ignore-files.html](https://nesbitt.io/2026/02/12/the-many-flavors-of-ignore-files.html)).

یک مثال خوب .npmignore است. اگر این فایل وجود نداشته باشد، npm به .gitignore رجوع می‌کند. اما به محض اضافه کردن .npmignore`، قوانین .gitignore` کاملاً جایگزین می‌شوند. نتیجه: ممکن است به‌طور تصادفی فایل‌هایی که در Git نادیده گرفته شده‌اند در پکیج منتشر شوند یا بالعکس، فایل‌های لازم منتشر نشوند. رفتار مشابه است، اما دقیقاً یکسان نیست و به راحتی می‌تواند باعث سردرگمی شود.

در مقاله، مجموعه‌ای از فایل‌های ignore ذکر شده‌اند:

* .gitignore — Git
* .dockerignore — Docker
* .npmignore — npm
* .prettierignore — Prettier
* .eslintignore — ESLint
* .stylelintignore — Stylelint
* .hgignore — Mercurial
* .containerignore — Podman/Buildah
* .gcloudignore — Google Cloud CLI
* .vercelignore — Vercel
* .slugignore — Heroku
* .cfignore — Cloud Foundry
* .helmignore — Helm
و غیره…

نتیجه‌گیری ساده است: نام یکسان، رفتار یکسان را تضمین نمی‌کند. اگر یک ابزار چیزی را «ناگهان» شامل یا نادیده می‌گیرد، تقریباً همیشه مسئله از جزئیات پیاده‌سازی منطق ignore است.

#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
This media is not supported in your browser
VIEW IN TELEGRAM
«چطور می‌توان یک آیکون را به فیلد ورودی اضافه کرد به‌طوری که تنها وقتی placeholder دیده می‌شود قابل مشاهده باشد و با وارد کردن متن ناپدید شود؟»

آیکون را داخل کانتینر label قرار دهید و سپس از pseudo-class :placeholder-shown روی فیلد ورودی استفاده کنید!

🔗https://codepen.io/alinaki/pen/xxMpgLK?editors=1100
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
3
اگر در پروژه Nuxt خود به پایگاه داده نیاز دارید (که معمولاً لازم است)، می‌توانید خیلی سریع آن را با استفاده از [Nuxt Hub](https://hub.nuxt.com) راه‌اندازی کنید.

این ابزار بر پایه Drizzle ORM کار می‌کند و از PostgreSQL**، **MySQL و SQLite پشتیبانی می‌کند.
همچنین، کار کردن به‌صورت محلی با Nuxt DevTools فوق‌العاده راحت است و تجربه توسعه را بسیار ساده می‌کند.

#️⃣#tool
👥@IR_javascript_group
🆔@IR_javascript
‏ Proxy در JavaScript 👨‍🏫

Proxy یک واسطه بین کد و شیء است. این ابزار عملیات‌های روی شیء (خواندن، نوشتن، فراخوانی، پیمایش) را رهگیری می‌کند و به شما اجازه می‌دهد واکنش به این عملیات‌ها را تغییر دهید—از طریق مجموعه‌ای از handlerها یا همان تله‌ها (traps).


const p = new Proxy(target, handler);


### چطور کار می‌کند؟

1️⃣ ابتدا یک شیء واقعی target می‌سازید؛
2️⃣ سپس handler را تعریف می‌کنید—شیئی با توابع رهگیری‌کننده مانند get, set, apply و غیره؛
3️⃣ فراخوانی new Proxy(target, handler) یک پروکسی برمی‌گرداند: هر عملی روی شیء ابتدا تله مربوطه را فراخوانی می‌کند و تصمیم می‌گیرد که عمل استاندارد انجام شود (با استفاده از Reflect) یا تغییر کند؛

### مهم‌ترین تله‌ها:

* get — رهگیری خواندن یک ویژگی؛
* set — رهگیری نوشتن و امکان اعتبارسنجی یا بلاک کردن مقدار؛
* apply — رهگیری فراخوانی توابع؛
* ownKeys / getOwnPropertyDescriptor — تأثیر روی Object.keys و سریال‌سازی؛

### مثال عملی:

const obj = { name: "Katya" };
const p = new Proxy(obj, {
get(t, prop){
return prop in t ? Reflect.get(t, prop) : "—not found—";
},
set(t, prop, val){
if(prop === "age" && typeof val !== "number")
throw TypeError("age must be number");
return Reflect.set(t, prop, val);
}
});


این Proxy شیء را «هوشمند» می‌کند:

* هنگام خواندن ویژگی‌های موجود نبود، مقدار پیش‌فرض برمی‌گرداند؛
* هنگام نوشتن، بررسی می‌کند که age حتماً عدد باشد؛

### نکات مهم:

✔️ ویژگی‌های non-configurable را پنهان نکنید و به شیء غیرقابل گسترش فیلد اضافه نکنید—در غیر این صورت TypeError خواهید گرفت؛
const obj = {};
Object.defineProperty(obj, "fixed", {
value: 42,
configurable: false // غیرقابل تغییر
});

// این کار باعث خطا می‌شود
delete obj.fixed; // TypeError

✔️ برای ارجاع صحیح از Reflect.* (https://t.me/IR_javascript/1328) استفاده کنید (به‌ویژه برای getterها و پروتوتایپ‌ها)؛
✔️ از Proxy در حلقه‌های داغ (حلقه‌هایی که خیلی زیاد اجرا می‌شوند) اجتناب کنید—ممکن است کارایی کاهش یابد؛

### جمع‌بندی:

‏Proxy یک نقطه کنترل مرکزی برای تمام تعاملات با شیء فراهم می‌کند، اما استفاده از آن باید آگاهانه باشد. کاربردهای اصلی شامل:

* واکنش‌پذیری (reactivity)
* اعتبارسنجی
* ثبت لاگ (logging)
* ویژگی‌های مجازی

در اکثر کارهای روزمره، استفاده از Proxy ممکن است اضافه باشد، اما دانستن نحوه عملکرد آن مهم است: بهتر است ابزار را بشناسید و استفاده نکنید تا اینکه در کد با آن مواجه شوید و نفهمید چه اتفاقی می‌افتد. 👍


#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
وقتی height: 100% روند چیدمان رو به هم ریخت 🙈

داشتم یه گرید ساده می‌ساختم: یه کانتینر با display: grid، ردیف‌ها با grid-template-rows: repeat(n, auto) و توی یه سلول، یه عنصری بود که براش height: 100% گذاشتم تا «قشنگ کش بیاد». تو کروم همه‌چیز عالی بود، ولی تو سافاری چیدمان به هم ریخت. ☹️

اولش فکر کردم: «خب، دیگه باگ مرورگره». ولی اگه یه کم عمیق‌تر بشیم، می‌بینیم که خبری از ماورا نیست: همه‌چیز به یه قانون CSS برمی‌گرده.

چه اتفاقی افتاد؟

‏height: 100% یعنی ۱۰۰٪ ارتفاع والد. و اینجا یه نکته کلیدی هست: ارتفاع درصدی فقط وقتی کار می‌کنه که والد یه ارتفاع مشخصی داشته باشه—منظور ارتفاعیه که بشه بدون در نظر گرفتن محتوا حسابش کرد.

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

✔️ ردیف منتظر می‌مونه تا اندازه بچه‌اش معلوم بشه،
✔️ بچه می‌خواد ۱۰۰٪ ارتفاع ردیف رو بگیره،
✔️ ولی ردیف هنوز ارتفاع خودش رو نمی‌دونه—و همه‌چیز قفل می‌کنه.

➡️ درصد اصلاً نمیدونه باید از چی حساب کنه.

چرا تو مرورگرهای مختلف نتیجه فرق می‌کنه؟

موتورهای مختلف ممکن است این جور چرخه‌های اندازه‌گیری رو جور متفاوتی حل کنن.
توی بعضی‌ها نتیجه «به‌نظر» نرمال میاد، توی بعضی دیگه مشکل خودش رو نشون میده.

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

خب، چطور این مشکل رو حل کنیم؟ باید به درصد یه تکیه‌گاه بدیم—یعنی ارتفاع والد رو مشخص و معین کنیم. 👍

#️⃣#tip #css
👥@IR_javascript_group
🆔@IR_javascript
ترکیب بهینه برای LCP#
برای تصویری که LCP را تعیین می‌کند، دو بخش مهم وجود دارد: دانلود و رندرینگ.

ویژگی fetchpriority="high" اولویت دانلود را بالا می‌برد، اما فقط زمانی که پارسر تصویر را در HTML پیدا کند. اگر تصویر دیر در سند ظاهر شود — مثلاً داخل یک کامپوننت، یک کاروسل یا به‌عنوان پس‌زمینه CSS — ممکن است مرورگر آن را دیر کشف کند.

استفاده از <link rel="preload"> در <head> این مشکل را حل می‌کند: دانلود تصویر قبل از رسیدن پارسر به آن شروع می‌شود.

<!-- در <head>: دانلود را هرچه زودتر آغاز کنید -->
<link rel="preload" as="image" href="hero.jpg" fetchpriority="high" />


<!-- در <body>: با مشخصه‌های مناسب رندرینگ -->
<img
src="hero.jpg"
alt="Hero"
width="یک‌هزار و دویست"
height="ششصد"
loading="eager"
decoding="sync"
fetchpriority="high"
/>


اگر از srcset با فرمت‌های مدرن استفاده می‌کنید، تگ preload از imagesrcset و imagesizes پشتیبانی می‌کند تا مرورگر دقیقاً همان منبعی را پیش‌دانلود کند که استفاده خواهد شد:

<link
rel="preload"
as="image"
imagesrcset="hero-400.avif 400w, hero-800.avif 800w, hero-1600.avif 1600w"
imagesizes="(max-width: 600px) 100vw, 800px"
fetchpriority="high"
/>


و وقتی این روش با <picture>`، فرمت‌های مدرن و `srcset همراه با اندازه‌ها ترکیب شود، تصویر در تمام جنبه‌ها به‌خوبی سرو می‌شود.


#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
شبکه‌های توزیع محتوا CDN برای تصاویر: راهکار عملی
مدیریت دستی همهٔ فرمت‌ها و اندازه‌های مختلف تصاویر پرهزینه است. شبکه‌های توزیع محتوا برای تصاویر مانند Cloudinary**، **Imgix یا Cloudflare Images این کار سنگین را خودکار می‌کنند: آن‌ها بهترین فرمت را برای هر مرورگر از طریق هدر Accept تشخیص می‌دهند، اندازه‌های مورد نیاز را بر اساس تقاضا تولید می‌کنند و تصاویر بهینه‌شده را از نزدیک‌ترین سرور ارائه می‌دهند.

برای مثال در Cloudinary کافی است پارامترها را در URL اعلام کنید:

<img
src="https://res.cloudinary.com/demo/image/upload/f_auto,q_auto,w_800/photo.jpg"
width="هشتصد"
height="ششصد"
alt="Photo"
loading="lazy"
decoding="async"
/>


پارامتر f_auto فرمت مناسب را بین AVIF، WebP یا JPEG بر اساس مرورگر انتخاب می‌کند. q_auto کیفیت را به‌صورت خودکار تنظیم می‌کند. همهٔ این‌ها بدون مدیریت چند فایل مختلف انجام می‌شود.



#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
ویژگی‌های عملکرد: loading`، `decoding و fetchpriority
این سه ویژگی بیشترین تأثیر را روی معیارهای عملکرد دارند و متأسفانه اغلب اشتباه پیکربندی می‌شوند.

loading#
کنترل می‌کند که مرورگر چه زمانی تصویر را دانلود کند.

<!--  همه تصاویر را بلافاصله بارگذاری می‌کند، حتی آن‌هایی که خارج از نما هستند -->
<img src="photo.jpg" alt="Photo" />

<!-- بارگذاری تصاویر خارج از نما را به تعویق می‌اندازد -->
<img src="photo.jpg" alt="Photo" loading="lazy" />


ویژگی loading="lazy" برای هر تصویری که در نمای اولیه نیست ایمن است. برای تصاویری که در نما هستند — به‌ویژه تصویر LCP — از loading="eager" استفاده کنید (یا به‌سادگی این ویژگی را حذف کنید که پیش‌فرض مرورگر است).

width و height#
اعلام ابعاد در HTML به مرورگر اجازه می‌دهد تا قبل از دانلود تصویر، فضا را رزرو کند و از جابجایی طرح‌بندی که باعث جریمه CLS می‌شود جلوگیری کند.

<!--  بدون ابعاد: جابجایی طرح هنگام بارگذاری تصویر -->
<img src="photo.jpg" alt="Photo" />

<!-- با ابعاد: فضا از ابتدا رزرو شده است -->
<img src="photo.jpg" alt="Photo" width="800" height="600" />


این ابعاد لازم نیست با اندازهٔ نهایی نمایش مطابقت داشته باشند (CSS این کار را انجام می‌دهد). مهم آن است که نسبت تصویر صحیح باشد تا مرورگر فضای رزرو شده را به‌درستی محاسبه کند.

decoding#
به مرورگر می‌گوید آیا می‌تواند تصویر را به‌صورت غیرهمزمان رمزگشایی کند بدون اینکه رشتهٔ اصلی را مسدود کند.

<!-- برای تصاویر غیرضروری: بدون مسدود کردن رندرینگ -->
<img src="photo.jpg" alt="Photo" decoding="async" />

<!-- برای تصویر LCP: رمزگشایی همزمان -->
<img src="hero.jpg" alt="Hero" decoding="sync" />


ویژگی decoding="async" برای تصاویر ثانویه گزینهٔ خوبی است. برای تصویر LCP**، `decoding="sync"` تضمین می‌کند که تصویر بلافاصله پس از دانلود نمایش داده شود.

fetchpriority#

اولویت دانلود را در سیستم اولویت‌دهی مرورگر تنظیم می‌کند.

<!--  مرورگر ممکن است اولویت را درست تعیین نکند -->
<img src="hero.jpg" alt="Hero" />

<!-- به‌صورت صریح اعلام می‌کند که حیاتی است -->
<img src="hero.jpg" alt="Hero" fetchpriority="high" />

<!-- برای تصاویر غیرضروری که ممکن است زودتر از نیاز دانلود شوند -->
<img src="banner.jpg" alt="Banner" fetchpriority="low" />


ویژگی fetchpriority="high" مخصوصاً وقتی مفید است که تصویر LCP داخل یک کاروسل باشد یا دیر در HTML ظاهر شود و مرورگر به‌صورت خودکار آن را با اولویت بالا تشخیص ندهد.

#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
فرمت‌های مدرن با <picture>
فرمت‌های مدرن مانند AVIF یا WebP فشرده‌سازی بسیار بهتری نسبت به JPEG یا PNG ارائه می‌دهند. المان <picture> به شما اجازه می‌دهد چندین منبع تعریف کنید و مرورگر اولین فرمتی را که پشتیبانی می‌کند، بارگذاری می‌کند.

فرمت JPEG XL نیز وعدهٔ بهبود فشرده‌سازی قابل توجهی می‌دهد، اما پشتیبانی مرورگر بسیار محدود است: Chrome آن را در سال دو هزار و بیست و دو حذف کرد و تنها به‌صورت آزمایشی در Firefox و Safari در دسترس است. بنابراین، ترکیب AVIF + WebP در حال حاضر امن‌ترین انتخاب است.

<!--  فقط JPEG، بدون جایگزین -->
<img src="photo.jpg" alt="Photo" />

<!-- AVIF اول، WebP به‌عنوان جایگزین، JPEG به‌عنوان پایه -->
<picture>
<source type="image/avif" srcset="photo.avif" />
<source type="image/webp" srcset="photo.webp" />
<img src="photo.jpg" width="800" height="600" alt="Photo" />
</picture>


ترتیب اهمیت دارد: مرورگر از بالا به پایین بررسی می‌کند و اولین فرمتی را که قادر به رندر آن است استفاده می‌کند. AVIF بهترین فشرده‌سازی را ارائه می‌دهد اما پشتیبانی آن کمتر از WebP است. JPEG همچنان به‌عنوان جایگزین جهانی باقی می‌ماند.

ترکیب پاسخگویی و فرمت‌های مدرن
هر دو تکنیک می‌توانند با هم ترکیب شوند تا تصویر مناسب از نظر فرمت و اندازه ارائه شود:

<picture>
<source
type="image/avif"
srcset="photo-400.avif 400w, photo-800.avif 800w, photo-1600.avif 1600w"
sizes="(max-width: 600px) 100vw, 50vw"
/>
<source
type="image/webp"
srcset="photo-400.webp 400w, photo-800.webp 800w, photo-1600.webp 1600w"
sizes="(max-width: 600px) 100vw, 50vw"
/>
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1600.jpg 1600w"
sizes="(max-width: 600px) 100vw, 50vw"
width="800"
height="600"
alt="Photo"
/>
</picture>


بله، مقدار کد بیشتر می‌شود، اما سرویس‌های CDN تصویر مانند Cloudinary این کار را به‌صورت خودکار انجام می‌دهند و از طریق هدر درخواست Accept فرمت بهینه را تشخیص می‌دهند، بدون اینکه نیاز باشد تمام این نسخه‌ها را دستی ایجاد کنید.


#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
تصاویر پاسخگو با srcset و `sizes`#
ویژگی `srcset` به شما اجازه می‌دهد چندین نسخه از یک تصویر تعریف کنید تا مرورگر مناسب‌ترین نسخه را بر اساس شرایط (چگالی صفحه، اندازهٔ viewport) انتخاب کند.

<!--  یک اندازه برای همه -->
<img src="hero.jpg" alt="Hero image" />

<!-- نسخه‌های مختلف برای چگالی‌ها و اندازه‌های متفاوت -->
<img
src="hero-800.jpg"
srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1600.jpg 1600w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 800px"
width="800"
height="600"
alt="Hero image"
/>


ویژگی sizes به مرورگر می‌گوید که تصویر در هر نقطهٔ شکست (breakpoint) چه مقدار فضا در طرح‌بندی اشغال خواهد کرد. بدون `sizes`، مرورگر فرض می‌کند تصویر ۱۰۰٪ عرض صفحه را اشغال می‌کند و ممکن است نسخه‌ای بزرگ‌تر از نیاز دانلود شود.


🔗https://joanleon.dev/en/guia-practica-elemento-img/
#️⃣#tip
👥@IR_javascript_group
🆔@IR_javascript
This media is not supported in your browser
VIEW IN TELEGRAM
کوتاه‌کردن انواع شناسه‌ها، مسیرهای فایل و نام فایل‌ها در وسط با css

🔗https://joanleon.dev/en/guia-practica-elemento-img/
#️⃣#code
👥@IR_javascript_group
🆔@IR_javascript