سلام! من سارا بحرانیام، کارشناس سئو از تیم «وزیر سئو». تا حالا برات پیش اومده که وارد سایتی بشی، مخصوصاً با موبایل، و قبل از اینکه اصلاً اسکرول کنی، مجبور بشی چند ثانیه منتظر لود شدن عکسهایی باشی که ته صفحه قرار دارن؟
این انتظار، هرچقدر هم کوتاه، دقیقاً همون چیزیه که کاربر رو کلافه میکنه و قاتل تجربه کاربری (UX) و سئوی سایته.
اینجاست که یه قهرمان بیصدا به اسم «بارگذاری تنبل» یا Lazy Loading وارد میشه. این تکنیک یکی از قویترین و ضروریترین استراتژیها برای بهینهسازی عملکرد (Core Web Vitals) و افزایش انفجاری سرعت سایته.
توی این راهنمای جامع، میخوام بهت نشون بدم Lazy Loading دقیقاً چیه، چطور قدم به قدم اون رو برای عکسها، ویدیوها و حتی تصاویر پسزمینه پیادهسازی کنی، چطور تستش کنی و مهمتر از همه، از چه اشتباهات مرگباری که به سئوت آسیب میزنه، دوری کنی. آمادهای که سرعت سایتت رو متحول کنیم؟
جدول کاربردی: انتخاب بهترین روش Lazy Loading
قبل از اینکه عمیق بشیم، این جدول به تو کمک میکنه تا با یه نگاه بفهمی برای هر سناریو باید از چه روشی استفاده کنی:
| سناریو (چیزی که میخوای لود کنی) | روش توصیهشده | چرا؟ (نکته کلیدی) |
| عکسهای پایین صفحه (Below-the-Fold) | loading=”lazy” (بومی) | سادهترین، سریعترین و استانداردترین روشه. بدون نیاز به جاوا اسکریپت. |
| عکس بزرگ بالای صفحه (LCP / Hero) | استفاده نکن (پیشفرض eager) | این عکس باید فوراً لود بشه. Lazy Load کردنش نمره LCP رو نابود میکنه. |
| ویدیوهای یوتیوب/آپارات (iframe) | تکنیک Facade (نما) | از لود شدن iframe سنگین تا قبل از کلیک کاربر جلوگیری میکنه و بهترین نتیجه رو میده. |
| تصاویر پسزمینه (CSS) | Intersection Observer + افزودن Class | روش بومی (loading=”lazy”) اینجا کار نمیکنه و باید با جاوا اسکریپت مدیریت بشه. |
بارگذاری تنبل (Lazy Loading) چیست و چرا برای Core Web Vitals حیاتی است؟
تا حالا برات پیش اومده که وارد صفحهای بشی، مخصوصاً از طریق موبایل، و مجبور بشی کلی منتظر بمونی تا عکسها یا ویدیوهایی که اصلاً هنوز بهشون نرسیدی و پایینتر صفحه هستن، لود بشن؟ این انتظار دقیقاً همون چیزیه که کاربر رو فراری میده و گوگل هم ازش متنفره.
اینجاست که «بارگذاری تنبل» یا Lazy Loading مثل یه قهرمان وارد میشه. این تکنیک یکی از حیاتیترین و موثرترین روشها برای بهینهسازی سرعته، چون مستقیماً روی معیارهای اصلی گوگل یعنی Core Web Vitals (هستههای حیاتی وب) تأثیر میذاره. بیایم دقیقتر ببینیم این تکنیک چطور کار میکنه و چرا انقدر برای سئوی سایتت مهمه.
تعریف بارگذاری تنبل: بارگذاری محتوا فقط زمانی که در دید کاربر قرار میگیرد
اگر بخوام خیلی ساده بگم: بارگذاری تنبل یعنی به مرورگر دستور میدی که «عجله نکن!».
به جای اینکه مرورگر مجبور باشه تمام المانهای صفحه (مخصوصاً عکسها، ویدیوها و iframeها) رو همون لحظه اول که کاربر وارد میشه دانلود و بارگذاری کنه، فقط المانهایی رو لود میکنه که در کادر دید اولیه کاربر (Viewport) هستن.
بعد، هرچقدر که تو به عنوان کاربر در صفحه اسکرول میکنی و به المانهای بعدی نزدیک میشی، مرورگر تازه شروع به بارگذاری اونها میکنه. این کار باعث میشه صفحه اولیه با سرعت فوقالعادهای باز بشه و منابع کاربر (مثل پهنای باند و باتری) الکی هدر نره.
تأثیر مستقیم Lazy Loading بر معیارهای LCP (Largest Contentful Paint) و TBT
اینجا دقیقاً همون جاییه که اهمیت Lazy Loading برای Core Web Vitals مشخص میشه:
- بهبود LCP (Largest Contentful Paint): معیار LCP مدت زمانی رو اندازه میگیره که طول میکشه تا بزرگترین المان محتوایی (معمولاً یه عکس بزرگ یا بنر هدر) در کادر دید کاربر نمایش داده بشه.
- سناریوی بد (بدون Lazy Load): مرورگر مجبوره همزمان هم اون بنر بزرگ (LCP) و هم ۱۰ تا عکس دیگهای که پایین صفحه هستن رو لود کنه. این «رقابت» برای منابع شبکه باعث میشه لود شدن اون بنر اصلی خیلی طول بکشه و نمره LCP تو خراب بشه.
- سناریوی خوب (با Lazy Load): وقتی تو عکسهای پایینی رو Lazy Load میکنی، مرورگر تمام تمرکز و پهنای باندش رو میذاره روی المانهای حیاتی بالای صفحه. در نتیجه، بنر LCP خیلی سریعتر لود میشه و نمره عالی میگیری.
- بهبود TBT (Total Blocking Time): این معیار (که به FID هم مرتبطه) نشون میده صفحه چقدر «قفل» بوده و به تعاملات کاربر (مثل کلیک) دیر جواب داده.
- سناریوی بد: وقتی مرورگر مجبوره کلی عکس و اسکریپت غیرضروری رو در لحظه اول لود کنه، «نخ اصلی» (Main Thread) مرورگر به شدت اشغال میشه. اگه کاربر همون موقع روی دکمهای کلیک کنه، هیچ اتفاقی نمیافته چون مرورگر سرش شلوغه!
- سناریوی خوب: Lazy Loading با کاهش چشمگیر بار اولیه، این نخ اصلی رو آزاد میکنه. در نتیجه TBT (زمان مسدود بودن) کاهش پیدا میکنه و صفحه خیلی زودتر «تعاملی» (Interactive) میشه.
تفاوت کلیدی loading=”lazy” (بومی) و loading=”eager” (پیشفرض)
خوشبختانه، این روزها پیادهسازی Lazy Loading برای عکسها و iframeها خیلی ساده شده و دیگه لزوماً نیازی به پلاگینهای جاوا اسکریپتی سنگین نیست. مرورگرهای مدرن این قابلیت رو به صورت «بومی» (Native) پشتیبانی میکنن.
تو میتونی با یه صفت HTML ساده به مرورگر بگی دقیقاً چکار کنه:
- loading=”lazy”: این همون چیزیه که ما میخوایم. با اضافه کردن این صفت به تگ <img> یا <iframe>، به مرورگر میگی: «این المان فعلاً حیاتی نیست. صبر کن تا کاربر بهش نزدیک بشه، بعد لودش کن.»
- loading=”eager”: این حالت پیشفرض مرورگره (حتی اگه هیچی ننویسی). یعنی به مرورگر میگی: «همین الان، بدون معطلی، این المان رو لود کن.»
نکته تخصصی: یادت باشه، هیچوقت المان LCP (معمولاً اولین عکس بزرگ بالای صفحه) رو Lazy Load نکن! یعنی برای اون عکس خاص، یا صفت loading=”eager” رو بذار یا اصلاً صفت loading رو قرار نده. اگه المان LCP رو Lazy Load کنی، نتیجه کاملاً معکوس میده و سرعتت رو خرابتر میکنه.
[فلوچارت] منطق تصمیمگیری مرورگر برای بارگذاری تنبل
شاید برات سوال باشه که مرورگر از کجا میفهمه «کی» باید لود کنه؟ «نزدیک شدن کاربر» دقیقاً یعنی چی؟
مرورگرها (مثل کروم) یه منطق داخلی و هوشمند دارن که بر اساس سرعت اینترنت کاربر و فاصله المان تا کادر دید (Viewport) تصمیم میگیرن.
این فلوچارت منطق مرورگر رو به این شکل نشون میده:
- مرورگر چک میکنه آیا المان صفت loading=”lazy” داره یا نه.
- اگه داشت، بارگذاری رو متوقف میکنه و منتظر میمونه.
- مرورگر دائماً موقعیت کاربر رو چک میکنه.
- به محض اینکه المان وارد یه «آستانه بارگذاری» (Load Threshold) میشه، مرورگر دستور لود رو صادر میکنه.
جالبه بدونی این «آستانه» بر اساس سرعت اینترنت متغیره. مثلاً در اینترنت سریع، ممکنه وقتی المان ۱۲۵۰ پیکسل با کادر دید فاصله داره لود بشه، اما در اینترنت کند، این فاصله به ۲۵۰۰ پیکسل افزایش پیدا میکنه تا مطمئن بشه تا وقتی کاربر به عکس میرسه، اون لود شده. این کار هوشمندانه باعث میشه تجربه کاربری حتی در سرعتهای پایین هم روان باشه.
روش اول (روش مدرن): پیادهسازی Native Lazy Loading تصاویر (توصیه گوگل)
خوشبختانه دورانی که برای پیادهسازی Lazy Loading باید از کتابخونههای سنگین جاوا اسکریپت استفاده میکردیم، گذشته. این روزها مرورگرهای مدرن خودشون این قابلیت رو به صورت «بومی» (Native) پشتیبانی میکنن.
این یعنی تو میتونی فقط با اضافه کردن یه صفت ساده به کد HTML، این قابلیت رو فعال کنی. این روش هم سرعت پیادهسازی رو به شدت بالا میبره و هم چون کد اضافهای به صفحه تحمیل نمیکنه، خودش باعث بهبود عملکرد و سرعت میشه.
استفاده از صفت loading=”lazy”: سادهترین و کارآمدترین روش
کل جادوی این روش، توی یه صفت به اسم loading خلاصه میشه. وقتی تو این صفت رو به تگ <img> (یا <iframe>) اضافه میکنی و مقدارش رو برابر lazy قرار میدی، مستقیماً به مرورگر دستور میدی که: «این عکس رو تا زمانی که کاربر به نزدیکی اون اسکرول نکرده، لود نکن.»
به همین سادگی! این روش فوقالعاده کارآمده چون:
- ساده است: نیاز به هیچ دانش جاوا اسکریپتی نداره.
- سبک است: هیچ فایل اضافهای به صفحه اضافه نمیکنه.
- هوشمند است: خود مرورگر بهترین زمان برای لود کردن عکس رو تشخیص میده.
[نمونه کد] پیادهسازی صحیح <img> با loading=”lazy”, width و height
فقط اضافه کردن loading=”lazy” کافی نیست. یکی از مهمترین نکات برای جلوگیری از به هم ریختن چیدمان صفحه (که باعث خراب شدن نمره CLS یا Cumulative Layout Shift میشه)، اینه که حتماً ابعاد عکس (طول و عرض) رو مشخص کنی.
وقتی تو width و height رو مشخص میکنی، مرورگر قبل از لود شدن عکس، فضای خالی لازم رو براش رزرو میکنه. اینطوری وقتی عکس لود میشه، محتوای صفحه بالا و پایین نمیپره.
نمونه کد صحیح:
<img src=”path/to/my-image.jpg”
alt=”توضیح کامل عکس برای سئو”
loading=”lazy”
width=”800″
height=”450″>
- src: آدرس عکست.
- alt: متن جایگزین، که برای سئو و دسترسیپذیری حیاتیه.
- loading=”lazy”: دستوری که منتظرش بودیم.
- width و height: ابعاد دقیق عکس برای جلوگیری از
مدیریت پشتیبانی مرورگرها (Browser Support) و Fallback
شاید بپرسی: «اگه یه کاربری با مرورگر خیلی قدیمی اومد چی؟»
خبر خوب اینه: مشکلی پیش نمیاد!
- مرورگرهای مدرن (کروم، فایرفاکس، اج، سافاری): همگی از loading=”lazy” پشتیبانی میکنن و عکس رو به صورت تنبل بارگذاری میکنن.
- مرورگرهای قدیمی (مثل اینترنت اکسپلورر): این مرورگرها اصلاً صفت loading=”lazy” رو نمیشناسن و به سادگی ازش عبور میکنن. در نتیجه، عکس رو مثل حالت عادی (Eager) همون اول لود میکنن.
این بهترین حالت Fallback (جایگزین) هست، چون عملکرد سایتت برای هیچ کاربری مختل نمیشه. فقط کاربرای قدیمیتر از مزیت Lazy Load بیبهره میمونن که این هم مشکلی از سمت تو نیست.
اشتباه حیاتی: چرا هرگز نباید تصاویر Above-the-Fold (مانند هیرو) را Lazy Load کنید؟
اینجا جاییه که خیلیا اشتباه میکنن و نتیجه معکوس میگیرن. لطفاً این نکته رو با دقت بخون:
تصاویر Above-the-Fold (بالای تا)، یعنی هر چیزی که کاربر در لحظه ورود به صفحه بدون اسکرول کردن میبینه (مثل لوگو، بنر اصلی یا همون Hero Image).
تو هرگز، هرگز و هرگز نباید این تصاویر رو Lazy Load کنی!
چرا؟ یادت میاد در مورد معیار LCP (Largest Contentful Paint) صحبت کردیم؟ LCP معمولاً همون عکس بزرگ بالای صفحه است. گوگل میخواد این عکس در سریعترین زمان ممکن لود بشه.
اگه تو روی این عکس loading=”lazy” بذاری، عمداً به مرورگر میگی که «برای لود کردنش صبر کن!» این کار باعث میشه نمره LCP سایتت به شدت افت کنه، چون مرورگر منتظر میمونه تا اول بفهمه عکس در کادر دید هست (که خب از اول بوده!) و بعد تازه شروع به لود کردنش میکنه.
قانون طلایی:
- تصاویر بالای صفحه (Above-the-Fold): همیشه باید loading=”eager” باشن (یا اصلاً صفت loading رو نداشته باشن که پیشفرضش همون Eager هست).
- تصاویر پایین صفحه (Below-the-Fold): همگی باید loading=”lazy” باشن.
روش دوم (راه حل جاوا اسکریپت): استفاده از Intersection Observer
این روش، کنترل کامل Lazy Loading رو به دست خودت میده. به جای اینکه به مرورگر بگی «خودت انجامش بده»، تو دقیقاً بهش میگی «چه زمانی و چطوری» این کار رو انجام بده. این API مدرن جاوا اسکریپت، ابزار اصلی ما برای این کار خواهد بود.
Intersection Observer API چیست و چرا از روشهای قدیمی (onscroll) بهتر است؟
اگه بخوام ساده بگم، Intersection Observer (ناظر تقاطع) یه API پیشرفته در مرورگرهاست که به کد جاوا اسکریپت تو اجازه میده بفهمه چه زمانی یک المان خاص وارد کادر دید کاربر (Viewport) شده یا از اون خارج شده.
چرا این API یک انقلاب محسوب میشه؟
چون قبل از این، ما مجبور بودیم از رویداد onscroll استفاده کنیم. این روش یه فاجعهی عملکردی بود! چرا؟
- روش قدیمی (onscroll): تصور کن با هر میلیمتر اسکرول کردن کاربر، صدها بار کد جاوا اسکریپت تو اجرا میشد تا چک کنه «آیا المان مورد نظر به صفحه رسیده؟». این کار منابع مرورگر رو میخورد و باعث کندی شدید و «لگ» (Lag) در اسکرول میشد.
- روش مدرن (Intersection Observer): این API اصلاً کاری به اسکرول نداره. تو فقط یک بار بهش میگی: «این المان رو زیر نظر بگیر (Observe کن) و فقط زمانی که وارد کادر دید شد، به من خبر بده (Callback رو اجرا کن)». این روش به شدت بهینهست، چون به صورت غیرهمزمان (Asynchronous) کار میکنه و اصلاً نخ اصلی (Main Thread) مرورگر رو درگیر نمیکنه.
الگوی پیادهسازی گام به گام: استفاده از data-src
الگوی استاندارد برای پیادهسازی Lazy Load با جاوا اسکریپت خیلی ساده و هوشمندانه است:
- آمادهسازی HTML: به جای اینکه آدرس عکس اصلی رو در صفت src بذاری، اون رو در یک صفتِ دیتای سفارشی مثل data-src قرار میدی.
- استفاده از Placeholder: در صفت src اصلی، یه عکس خیلی کمحجم (مثلاً یه نسخه خیلی کوچیک و تار از همون عکس، یا یه لوگوی خاکستری) قرار میدی تا فضای عکس خالی نمونه.
- انتخاب المانها: با جاوا اسکریپت، تمام عکسهایی که قراره Lazy Load بشن رو انتخاب میکنی (مثلاً اونهایی که کلاس .lazy-load دارن).
- تنظیم Observer: یه IntersectionObserver جدید میسازی.
- اجرای دستور: وقتی Observer بهت خبر داد که عکس وارد کادر دید شده:
- آدرس رو از data-src میخونی.
- اون آدرس رو در صفت src قرار میدی.
- مرورگر به طور خودکار شروع به لود کردن عکس اصلی میکنه.
- پاکسازی: بعد از اینکه عکس لود شد، دیگه نیازی نیست اون رو زیر نظر داشته باشی، پس unobserve میکنی تا منابع الکی مصرف نشه.
[نمونه کد] پیادهسازی Lazy Loading با Intersection Observer (کد خالص JS)
فرض کنیم این HTML رو داریم:
<img data-src=”path/to/real-image-1.jpg”
src=”placeholder-image.gif”
alt=”توضیحات عکس اول”
class=”lazy-image”
width=”600″
height=”400″>
<img data-src=”path/to/real-image-2.jpg”
src=”placeholder-image.gif”
alt=”توضیحات عکس دوم”
class=”lazy-image”
width=”600″
height=”400″>
حالا این کد جاوا اسکریپت رو به صفحهات اضافه میکنی:
document.addEventListener(“DOMContentLoaded”, () => {
// 1. تمام عکسهای تنبل رو انتخاب کن
const lazyImages = document.querySelectorAll(“img.lazy-image”);
// 2. تنظیمات Observer (مثلاً میتونی بگی 200 پیکسل مونده به المان، لودش کن)
const options = {
rootMargin: “0px 0px 200px 0px”, // 200px قبل از رسیدن به پایین ویوپورت
};
// 3. Observer رو بساز
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
// 4. چک کن آیا المان وارد کادر دید شده؟
if (entry.isIntersecting) {
const image = entry.target;
// 5. آدرس اصلی رو از data-src به src منتقل کن
image.src = image.dataset.src;
// 6. کلاس lazy رو حذف کن (اختیاری)
image.classList.remove(“lazy-image”);
// 7. این المان رو دیگه زیر نظر نگیر
observer.unobserve(image);
}
});
}, options);
// 8. به Observer بگو که همه عکسهای تنبل رو زیر نظر بگیره
lazyImages.forEach(image => {
imageObserver.observe(image);
});
});
معرفی کتابخانههای سبک جاوا اسکریپت (مانند lazysizes.js) برای سناریوهای پیچیده
خب، نوشتن کد بالا خیلی هم سخت نبود، درسته؟ اما اگه سناریوی تو پیچیدهتر باشه چی؟
- اگه بخوای از srcset (تصاویر واکنشگرا) پشتیبانی کنی؟
- اگه بخوای تصاویر پسزمینه CSS رو Lazy Load کنی؟
- اگه محتوای تو بعداً توسط جاوا اسکریپت به صفحه اضافه بشه (مثل اسکرول بینهایت)؟
- اگه بخوای یه Fallback بیدردسر برای مرورگرهای خیلی قدیمی (که Intersection Observer ندارن) داشته باشی؟
اینجاست که کتابخونههای سبک و بهینه وارد میشن. به جای اینکه چرخ رو از اول اختراع کنی، میتونی از یه ابزار تست شده استفاده کنی.
معرفی lazysizes.js: یکی از محبوبترین، سبکترین (زیر ۲ کیلوبایت!) و قویترین کتابخونهها برای این کاره. lazysizes به شدت هوشمنده. فقط کافیه فایلش رو به صفحهات اضافه کنی و به جای data-src از data-src و به جای کلاس lazy-image از کلاس lazyload استفاده کنی. خودش بقیهی کارها رو به بهترین شکل ممکن انجام میده، از جمله پشتیبانی کامل از srcset و شناسایی خودکار المانهای جدید.
چه زمانی از کتابخونه استفاده کنیم؟ اگه فقط چند تا عکس ساده داری، همون روش Native یا کد خالص JS عالیه. اما اگه سایتت پیچیدهتره (مثلاً فروشگاهی یا مجلهای)، استفاده از یه کتابخونه بهینه مثل lazysizes میتونه در زمانت صرفهجویی کنه و نتیجه بهتری هم بهت بده.
تکنیکهای تخصصی Lazy Loading ویدئوها و iframeها (یوتیوب، آپارات، ویمئو)
وقتی تو یه ویدیو از یوتیوب رو در صفحهات «Embed» میکنی، در واقع داری یه درِ بزرگ به یه دنیای دیگه باز میکنی. مرورگر مجبوره نهتنها خود ویدیو، بلکه کل پلیر یوتیوب، اسکریپتهای ردیابی، فایلهای CSS و کلی چیز دیگه رو لود کنه. این یعنی یه فاجعه برای سرعت!
چالش iframe: چرا ویدئوها قاتل سرعت صفحه هستند؟
مشکل اصلی اینجاست:
یک تگ <iframe> ساده از یوتیوب یا آپارات، به تنهایی میتونه صدها کیلوبایت (و گاهی بیش از یک مگابایت!) دیتای اضافه به صفحهی تو تحمیل کنه. این اتفاق حتی اگه کاربر اصلاً روی دکمه Play کلیک نکنه هم میفته!
این بار سنگین، مستقیماً «نخ اصلی» مرورگر (Main Thread) رو برای چند ثانیه اشغال میکنه و معیارهای حیاتی تو مثل TBT (Total Blocking Time) و LCP (اگه ویدیو بالای صفحه باشه) رو نابود میکنه.
روش ۱: استفاده از loading=”lazy” برای تگ iframe (پشتیبانی مدرن)
دقیقاً مثل تصاوی، مرورگرهای مدرن به تو اجازه میدن که صفت loading=”lazy” رو به تگ <iframe> هم اضافه کنی.
<iframe src=”httpsYOUR-VIDEO-URL…”
loading=”lazy”
width=”560″
height=”315″
title=”توضیح کامل ویدیو”>
</iframe>
این روش چکار میکنه؟ این کار به مرورگر میگه که لود کردن تمام اون منابع سنگین iframe رو تا زمانی که کاربر به نزدیکی اون اسکرول نکرده، به تعویق بندازه.
خوبه؟ بله، خیلی بهتر از هیچیه و سادهترین راهه. عالیه؟ نه! چون به محض اینکه کاربر به ویدیو میرسه (حتی قبل از کلیک)، باز هم تمام اون منابع سنگین لود میشن. ما میتونیم از این هم بهینهتر عمل کنیم.
روش ۲ (تجربه عملی): تکنیک Facade (نما) – بارگذاری iframe فقط پس از کلیک
اینجا دیگه تخصص واقعی معنی پیدا میکنه. تکنیک نما (Facade) یکی از بهترین استراتژیها برای بهینهسازی سرعته.
ایده اینه: «تا زمانی که کاربر نخواسته، هیچی لود نکن!»
ما به جای لود کردن iframe سنگین، فقط یه عکس سبک (که دقیقاً شبیه تصویر کوچک یا Thumbnail همون ویدیوئه) به همراه یه آیکون Play جعلی به کاربر نشون میدیم. این فقط یه «نما» از ویدیوئه، نه خود ویدیو.
روند کار چطوریه؟
- صفحه لود میشه -> فقط یه عکس سبک + آیکون Play لود میشه (سرعت عالی).
- کاربر روی این «نمای» جعلی کلیک میکنه.
- تازه در اون لحظه، یه اسکریپت ساده جاوا اسکریپت اجرا میشه، اون عکس رو حذف میکنه و تگ <iframe> واقعی رو جایگزینش میکنه (و معمولاً با autoplay=1 تا بلافاصله پخش بشه).
این روش بهترین تجربه کاربری و بهترین نمره عملکرد رو به تو میده، چون سنگینترین بخش ماجرا (iframe) فقط و فقط در صورت نیاز واقعی کاربر لود میشه.
[نمونه کد] جایگزینی iframe سنگین یوتیوب با یک تصویر Thumbnail و دکمه Play
بیا یه نمونه سادهاش رو با هم ببینیم.
- کد HTML: ما از data-src برای نگهداری آدرس iframe واقعی استفاده میکنیم.
<div class=”video-facade”
data-src=”https://www.youtube.com/embed/VIDEO_ID_HERE?autoplay=1″
style=”background-image:url(‘https://i.ytimg.com/vi/VIDEO_ID_HERE/hqdefault.jpg’)”>
<div class=”play-button”></div>
</div>
- کد CSS (برای ظاهر):
.video-facade {
position: relative;
width: 100%;
max-width: 560px; /* اندازه دلخواه */
height: 315px; /* حفظ نسبت 16:9 */
background-size: cover;
background-position: center;
cursor: pointer;
}
.play-button {
/* یه دکمه Play ساده با CSS */
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 0;
height: 0;
border-top: 30px solid transparent;
border-bottom: 30px solid transparent;
border-left: 45px solid #fff;
opacity: 0.8;
transition: opacity 0.2s;
}
.video-facade:hover .play-button {
opacity: 1;
}
- کد JavaScript (جادوی اصلی):
document.addEventListener(“DOMContentLoaded”, () => {
// همه ویدیو-نما ها رو پیدا کن
const facades = document.querySelectorAll(“.video-facade”);
facades.forEach(facade => {
facade.addEventListener(“click”, () => {
// 1. یه تگ iframe بساز
const iframe = document.createElement(“iframe”);
iframe.setAttribute(“src”, facade.dataset.src);
iframe.setAttribute(“frameborder”, “0”);
iframe.setAttribute(“allow”, “accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture”);
iframe.setAttribute(“allowfullscreen”, “”);
iframe.setAttribute(“width”, “100%”); // برای واکنشگرایی
iframe.setAttribute(“height”, facade.offsetHeight); // ارتفاع رو از div قبلی بگیر
// 2. نما رو با iframe واقعی جایگزین کن
facade.parentNode.replaceChild(iframe, facade);
});
});
});
پیادهسازی Lazy Loading برای تصاویر پسزمینه (CSS background-image)
همونطور که گفتم، تصاویری که مستقیماً در CSS با background-image لود میشن، از چشم ابزارهای بهینهسازی خودکار دور میمونن، اما مرورگر مجبوره اونها رو دانلود کنه. اگه این تصاویر پایین صفحه باشن، لود کردنشون در ابتدای کار، یعنی هدر دادن خالص منابع.
چرا loading=”lazy” برای تصاویر CSS کار نمیکند؟
این یه سوال عالیه و جوابش یه نکته فنی مهم داره.
خیلی ساده بگم: چون loading=”lazy” یک صفت (Attribute) در HTML است، نه یک خاصیت (Property) در CSS.
این صفت به طور خاص برای المانهای HTML مثل <img> و <iframe> طراحی شده. مرورگر وقتی داره کدهای HTML رو میخونه، به این صفت میرسه و تصمیم میگیره که اون المان رو لود کنه یا نه.
اما background-image اصلاً یه المان HTML نیست! اون یه دستوره که داخل فایل CSS برای یه المان (مثلاً یه <div>) نوشته شده. مرورگر تا زمانی که فایل CSS رو کامل نخونه و شروع به رندر کردن صفحه نکنه، اصلاً متوجه نمیشه که قراره عکسی رو به عنوان پسزمینه لود کنه. در نتیجه، loading=”lazy” روی یه <div> یا section هیچ تأثیری روی background-image اون نداره.
استفاده از Intersection Observer برای افزودن یک کلاس (Class) به عنصر
خب، اگه روش اتوماتیک مرورگر کار نمیکنه، ما باید خودمون دست به کار بشیم و به مرورگر دستور بدیم کی لود کنه.
بهترین و بهینهترین راه برای این کار، همون دوست قدیمیه ما، Intersection Observer API هست.
استراتژی ما اینه:
- در CSS، ما عکسی رو مستقیماً لود نمیکنیم.
- ما یه کلاس «آمادهباش» (مثلاً .lazy-bg) به المان HTML مورد نظرمون میدیم.
- بعد، یه کلاس «اجرایی» (مثلاً .is-visible یا .load-now) در CSS تعریف میکنیم که اون شامل دستور background-image واقعی هست.
- با استفاده از IntersectionObserver، المان .lazy-bg رو زیر نظر میگیریم.
- به محض اینکه اون المان وارد کادر دید کاربر شد، با جاوا اسکریپت کلاس .is-visible رو بهش اضافه میکنیم.
- همین! مرورگر بلافاصله کلاس جدید رو میبینه و تازه اون موقع شروع به لود کردن عکس پسزمینه میکنه.
[نمونه کد] بارگذاری تنبل background-image با جاوا اسکریپت
بیا این استراتژی رو در عمل ببینیم. این یه نمونه کد کامل و تمیزه:
۱. کد HTML: یک سکشن داریم که میخوایم پسزمینه داشته باشه. فقط کلاس «آمادهباش» رو بهش میدیم.
<section class=”hero-section lazy-background”>
<h2>به وبسایت ما خوش آمدید</h2>
</section>
۲. کد CSS: اینجا جادوی اصلی اتفاق میفته.
/* این کلاس اولیه ماست – هیچ عکسی اینجا نیست */
.lazy-background {
min-height: 400px; /* یه ارتفاعی بهش میدیم که فضا رو نگه داره */
background-color: #f0f0f0; /* یه رنگ پسزمینه موقت */
/* میتونیم یه انیمیشن لودینگ هم بذاریم */
}
/* این کلاس “اجرایی” ماست.
فقط زمانی که این کلاس اضافه بشه، عکس لود میشه.
*/
.lazy-background.is-visible {
background-image: url(‘path/to/heavy-background-image.jpg’);
background-size: cover;
background-position: center;
}
۳. کد JavaScript (استفاده از Intersection Observer): این اسکریپت رو در فوتر سایتت قرار بده.
document.addEventListener(“DOMContentLoaded”, () => {
// 1. تمام المانهایی که پسزمینه تنبل دارن رو انتخاب کن
const lazyBackgrounds = document.querySelectorAll(“.lazy-background”);
// 2. تنظیمات Observer
const options = {
rootMargin: “0px 0px 100px 0px”, // 100px قبل از رسیدن لود کن
};
// 3. Observer رو بساز
const bgObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
// 4. آیا المان وارد کادر دید شده؟
if (entry.isIntersecting) {
const element = entry.target;
// 5. کلاس اجرایی رو اضافه کن!
element.classList.add(“is-visible”);
// 6. کارمون با این المان تمومه، دیگه زیر نظر نگیرش
observer.unobserve(element);
}
});
}, options);
// 7. به Observer بگو همه المانها رو زیر نظر بگیره
lazyBackgrounds.forEach(el => {
bgObserver.observe(el);
});
});
چگونه Lazy Loading را تست و دیباگ کنیم؟ (اطمینان از عملکرد صحیح)
بعد از اینکه هر کدوم از روشهای Lazy Loading (چه Native و چه جاوا اسکریپت) رو پیاده کردی، باید مطمئن بشی که: ۱. واقعاً داره کار میکنه و جلوی لود شدن عکسها رو میگیره. ۲. عکسها دقیقاً قبل از رسیدن کاربر بهشون، لود میشن (نه خیلی زود، نه خیلی دیر). ۳. به سئوی تصاویرت آسیبی وارد نمیکنه.
این سه تا ابزار اصلی تو برای این کاره:
استفاده از تب Network در Chrome DevTools (بررسی Waterfall بارگذاری)
این بهترین دوست تو برای چک کردن اینه که دقیقاً چه اتفاقی در پشت صحنه میافته.
چطور این کار رو بکنی؟
- توی مرورگر کروم، روی صفحهات راست کلیک کن و Inspect رو بزن.
- به تب (زبانه) Network برو.
- کش مرورگر رو غیرفعال کن (تیک Disable cache رو بزن) تا نتایج واقعی رو ببینی.
- در فیلتر، روی Img کلیک کن تا فقط تصاویر رو بهت نشون بده.
- حالا، صفحهات رو رفرش کن (Ctrl+R یا Cmd+R) در حالی که DevTools بازه.
دنبال چی بگردیم؟
- سناریوی ایدهآل (Lazy Load فعال): در لحظه لود صفحه، تو فقط باید تصاویر بالای صفحه (Above-the-Fold) رو در لیست ببینی. ستون Waterfall (آبشار) باید نشون بده که لود شدن این عکسها همزمان با لود صفحه شروع شده.
- تست اسکرول: حالا شروع کن به آرامی در صفحه اسکرول کن. همونطور که اسکرول میکنی، باید ببینی که اسم فایلهای عکسهای جدید، یکییکی به لیست تب Network اضافه میشن و ستون Waterfall نشون میده که دانلودشون دقیقاً همون موقع شروع شده.
- سناریوی بد (Lazy Load غیرفعال): اگه همون لحظه اول که صفحه رو رفرش کردی، لیست بلندی از تمام عکسهای صفحه رو دیدی که همزمان شروع به لود شدن کردن، یعنی Lazy Loading تو اصلاً کار نمیکنه!
تحلیل گزارش Lighthouse و بررسی بخش “Defer offscreen images”
Lighthouse ابزار حسابرسی خود گوگله که مستقیماً داخل Chrome DevTools قرار داره. این ابزار بهت نمیگه «چطوری» کار میکنی، بلکه میگه «نتیجه کارت» چقدر خوبه.
چطور این کار رو بکنی؟
- در DevTools، به تب Lighthouse برو.
- مطمئن شو که دستهبندی (Category) Performance تیک خورده باشه.
- روی دکمه Analyze page load کلیک کن و منتظر بمون تا گزارش آماده بشه.
- در گزارش، به بخش Opportunities (فرصتها) برو.
دنبال چی بگردیم؟ دنبال توصیهای به اسم “Defer offscreen images” (تصاویر خارج از صفحه را به تعویق بینداز) بگرد.
- سناریوی ایدهآل: اگه Lazy Loading رو درست پیاده کرده باشی، این بخش اصلاً نباید وجود داشته باشه، یا نهایتاً یکی دو تا عکس رو نشون بده (که طبیعیه).
- سناریوی بد: اگه این توصیه رو دیدی و لیستی از عکسها رو بهت نشون داد، یعنی تو هنوز عکسهایی داری که در دید کاربر نیستن (Offscreen) اما دارن همون اول لود میشن. Lighthouse حتی بهت میگه که با Lazy Load کردنشون چقدر میتونی در زمان لود صفحه صرفهجویی کنی.
اطمینان از ایندکس تصاویر توسط Googlebot (بررسی سئوی تصاویر Lazy Load شده)
این یکی از بزرگترین ترسها در مورد Lazy Loading هست: «اگه گوگل نتونه عکسهای منو ببینه و ایندکسشون نکنه چی؟»
خبر خوب: گوگل خیلی وقته که با Lazy Loading مشکلی نداره، به شرطی که درست پیادهسازیش کنی.
چطور چک کنیم؟
- روش Native (loading=”lazy”): اگه از این روش استفاده میکنی، اصلاً نگران نباش. گوگل کاملاً این صفت رو درک میکنه و به درستی هم اسکرول میکنه و هم تصاویر رو میبینه.
- روش Intersection Observer (جاوا اسکریپت): اینجا باید کمی بیشتر مراقب باشی. گوگل میتونه جاوا اسکریپت رو رندر کنه، اما باید مطمئن بشی که:
- لینک عکسها در کد HTML وجود داشته باشه (مثلاً در data-src).
- مهم: از تگ <a> (لینک) برای Lazy Load کردن عکسها استفاده نکرده باشی. همیشه از تگ <img> با data-src یا از CSS Background با روشی که گفتم استفاده کن.
ابزار تست نهایی:
- URL Inspection Tool (در سرچ کنسول): آدرس صفحهات رو در سرچ کنسول وارد کن. روی “Live Test” کلیک کن. بعد از اینکه تست تموم شد، برو به بخش Screenshot و HTML رندر شده.
- تست اسکرول مجازی: گوگل بات (Googlebot) در زمان رندر کردن، صفحه رو به صورت مجازی تا انتها اسکرول میکنه تا محتوایی که با جاوا اسکریپت لود میشه (از جمله عکسهای Lazy Load شده تو) رو ببینه.
- چک کردن HTML رندر شده: در نتیجه Live Test، ببین آیا تگهای <img> تو که اول data-src داشتن، حالا به src تبدیل شدن یا نه. اگه تبدیل شده باشن، یعنی گوگل هم تونسته اونها رو ببینه و ایندکس میکنه.
اشتباهات رایج در پیادهسازی (که به سئو و تجربه کاربری آسیب میزند)
انجام دادن Lazy Loading به شکل اشتباه، میتونه بدتر از انجام ندادنش باشه. این اشتباهات مستقیماً معیارهای Core Web Vitals رو هدف قرار میدن و تجربه کاربری رو خراب میکنن.
۱. عدم تعیین ابعاد (width/height) و ایجاد CLS (Cumulative Layout Shift)
این فاجعهبارترین و متأسفانه رایجترین اشتباهه.
- اشتباه چیه؟ اینکه تو تگ <img> رو Lazy Load میکنی، اما به مرورگر نمیگی که این عکس قراره چقدر فضا اشغال کنه (یعنی width و height رو مشخص نمیکنی).
- چه اتفاقی میفته؟ صفحه لود میشه. مرورگر یه فضای خالی بدون ارتفاع برای عکس در نظر میگیره. کاربر شروع به خوندن متن میکنه. همینطور که داره اسکرول میکنه، به عکس میرسه و Lazy Load فعال میشه. عکس لود میشه و ناگهان در صفحه ظاهر میشه و تمام متنی که کاربر داشت میخوند رو به پایین هل میده!
این «پرش محتوا» همون چیزیه که گوگل بهش میگه CLS (Cumulative Layout Shift) و یکی از سه معیار اصلی Core Web Vitals هست. این تجربه برای کاربر فوقالعاده آزاردهنده است و گوگل به شدت باهاش برخورد میکنه.
- راهحل درست: همیشه، همیشه، همیشه صفات width و height رو برای تگهای <img> مشخص کن. (یا از تکنیک مدرنتر CSS aspect-ratio استفاده کن). اینطوری مرورگر قبل از لود شدن عکس، یه جعبه خالی با ابعاد دقیق رزرو میکنه و هیچ پرشی اتفاق نمیافته.
۲. Lazy Loading تمام تصاویر صفحه (حتی تصاویر بالای صفحه)
این اشتباه، نشونهی درک نکردن هدف اصلی Lazy Loading هست.
- اشتباه چیه؟ اینکه یه اسکریپت یا پلاگین نصب میکنی که تمام عکسهای سایت، از جمله لوگو، بنر هدر (Hero Image) و هر عکسی که در بالای صفحه (Above-the-Fold) هست رو loading=”lazy” میکنه.
- چه اتفاقی میفته؟ یادت میاد در مورد LCP (Largest Contentful Paint) صحبت کردیم؟ LCP معمولاً همون عکس بزرگ بالای صفحه است. هدف ما اینه که LCP سریعترین المانی باشه که لود میشه. وقتی تو این عکس رو Lazy Load میکنی، عمداً به مرورگر دستور میدی: «برای لود کردن مهمترین و اولین عکس صفحه صبر کن!» این کار مستقیماً نمره LCP تو رو خراب میکنه و نتیجه کاملاً معکوس میده.
- راهحل درست: Lazy Loading فقط برای تصاویر پایین صفحه (Below-the-Fold) هست؛ یعنی تصاویری که کاربر برای دیدنشون باید اسکرول کنه. تمام المانهای حیاتی بالای صفحه (مخصوصاً المان LCP) باید به صورت Eager (پیشفرض مرورگر یا loading=”eager”) لود بشن.
۳. استفاده از اسکریپتهای سنگین و قدیمی جاوا اسکریپت برای پیادهسازی
این اشتباه مثل اینه که برای خاموش کردن یه آتیش کوچیک، یه سطل بنزین روش بپاشی!
- اشتباه چیه؟ اینکه به جای استفاده از روش Native و سبک مرورگر (loading=”lazy”) یا Intersection Observer مدرن، میری سراغ یه پلاگین jQuery قدیمی یا یه کتابخونه جاوا اسکریپت ۱۰ ساله که خودش ۲۰۰ کیلوبایت حجم داره!
- چه اتفاقی میفته؟ هدف ما از Lazy Loading، کاهش بار اولیه صفحه و آزاد کردن «نخ اصلی» (Main Thread) مرورگر بود. اما حالا یه اسکریپت سنگین اضافه کردی که خودش باعث مسدود شدن این نخ اصلی میشه! این کار مستقیماً نمرههای TBT (Total Blocking Time) و FID (First Input Delay) رو خراب میکنه. یعنی کاربر روی دکمهای کلیک میکنه اما سایت هنگ کرده، چون مرورگر درگیر اجرای اون اسکریپت سنگین Lazy Loading توئه.
- راهحل درست:
- اولویت اول: همیشه از Native Lazy Loading (loading=”lazy”) استفاده کن. سبکه، سریعه و هیچی به صفحهات اضافه نمیکنه.
- اولویت دوم: اگه مجبوری از جاوا اسکریپت استفاده کنی (مثلاً برای background-image)، فقط از Intersection Observer API (که کدش رو دیدی) یا یه کتابخونه فوقسبک و مدرن مثل lazysizes استفاده کن.
جمعبندی: Lazy Loading، یه تکنیک ساده با تأثیر بزرگ
خب، اینم از سفر کامل ما به دنیای Lazy Loading! با هم دیدیم که چطور با چند تا تکنیک ساده و هوشمندانه میتونی جلوی لود شدن منابع غیرضروری در لحظه اول رو بگیری و صفحهات رو مثل موشک سریع کنی.
یادت باشه، تو دنیای امروز که کاربران (و گوگل) هیچ صبری برای سایتهای کند ندارن، بارگذاری تنبل دیگه یه تکنیک لوکس یا اختیاری نیست؛ یه ضرورت مطلقه. این کار مستقیماً روی تجربه کاربری، نمرههای Core Web Vitals (هستههای حیاتی وب) و در نهایت، رتبه سئوی تو تأثیر مثبت میذاره.
از همین امروز شروع کن. برو سراغ صفحههای سنگین سایتت، از ابزارهایی که گفتم (مثل تب Network) استفاده کن تا گلوگاهها رو پیدا کنی و حواست به اشتباهات رایج (مثل لود نکردن ابعاد عکس یا لود کردن عکس هیرو) باشه.
اگه سوالی در مورد پیادهسازی این تکنیکها داشتی، من همینجا هستم تا کمکت کنم!
سوالات متداول (FAQ)
آیا Lazy Loading برای سئو خوب است؟
بله، عالیه! به شرطی که درست پیادهسازی بشه. گوگلبات (خزنده گوگل) کاملاً توانایی اسکرول کردن و دیدن محتوای Lazy Load شده رو داره. از اونجایی که Lazy Loading سرعت صفحه رو (که یه فاکتور رتبهبندیه) به شدت بهبود میده، مستقیماً به سئو کمک میکنه.
آیا Lazy Loading روی همه معیارهای Core Web Vitals تأثیر داره؟
بله، روی هر سه معیار تأثیر کلیدی داره:
- LCP رو بهبود میده (چون رقابت برای منابع رو کم میکنه).
- CLS رو کنترل میکنه (به شرطی که حتماً width و height رو مشخص کنی).
- TBT/FID رو بهبود میده (چون از لود شدن اسکریپتها و iframeهای سنگین در لحظه اول جلوگیری میکنه).
سادهترین راه برای فعالسازی Lazy Loading چیست؟
اگه از وردپرس نسخه ۵.۵ به بالا استفاده میکنی، خود وردپرس به طور خودکار صفت loading=”lazy” رو به عکسهات اضافه میکنه. اگه خودت کدنویسی میکنی، استفاده از همین صفت loading=”lazy” روی تگ <img> سادهترین و بهترین راهه.
آیا باید ویدیوها رو هم Lazy Load کنم؟
حتماً! ۱۰۰ درصد. ویدیوها (مخصوصاً iframeها) خیلی سنگینتر از عکسها هستن و بار زیادی به صفحه تحمیل میکنن. استفاده از تکنیک Facade (نما) که توضیح دادم، یکی از بزرگترین بردهاییه که میتونی برای سرعت صفحهات به دست بیاری.