پرش به محتوا
سئو و سرعت سایت

پرش چیدمان صفحه هنگام بارگذاری؛ علت CLS و راه رفعش

۹ دقیقه مطالعه

پرش چیدمان صفحه یعنی وسط خوندن یا کلیک، همه چیز یهو جابه جا می شه. توضیح می دیم CLS از کجا میاد و با جای ثابت برای تصویر، فونت و تبلیغ چطور درست می شه.

صفحه وب با متنی که پس از رسیدن تصویر به پایین رفته است

پرش چیدمان صفحه وقتی اتفاق می افته که مرورگر برای یه عنصر جا نگه نداشته و اون عنصر دیرتر می رسه. تصویر، فونت، بنر یا تبلیغ وارد می شه و بقیه محتوا رو هل می ده. اسم فنیش CLS (Cumulative Layout Shift) هست؛ امتیازی که جابه جایی ناخواسته عناصر رو می سنجه. راه رفعش ساده است: قبل از رسیدن هر عنصر، جای ثابتی براش مشخص کن. یعنی برای تصویر ابعاد، برای فونت یه جایگزین نزدیک به اصلی و برای تبلیغ یه قاب با اندازه مشخص.

نشانه: صفحه زیر دستت جابه جا می شه

داری یه پاراگراف رو می خونی و یهو متن می ره پایین. یا دکمه «افزودن به سبد» درست لحظه ای که می خوای کلیک کنی یه خط جابه جا می شه و می خوره به لینک بغلی. کاربر دقیقاً همین رو حس می کنه.

مثل این می مونه که وسط خرید، قفسه های مغازه رو جابه جا کنن. دستت به سمت یه جنس دراز شده و اون جنس دیگه اونجا نیست.

CLS همین جابه جایی ها رو به یه عدد تبدیل می کنه. هرچی عدد کمتر باشه، صفحه پایدارتره. طبق راهنمای فعلی گوگل، ۰٫۱ یا کمتر «خوب» حساب می شه. این آستانه ممکنه عوض بشه، پس یه نگاه هم به مستندات web.dev بنداز.

اهمیتش دو جاست. اول تجربه کاربره: کلیک اشتباه، گم شدن جای خوندن و اعتماد کمتر به سایت. تو فروشگاه این وضع بدتره، چون یه کلیک اشتباه می تونه کاربر رو از مسیر خرید بیرون ببره. دوم اینکه CLS یکی از شاخص های Core Web Vitals هست و گوگل اون ها رو برای تجربه صفحه در نظر می گیره.

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

قبل از هر تغییری اندازه بگیر

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

داده میدانی و داده آزمایشگاهی چه فرقی دارن؟

داده میدانی از کاربرهای واقعی میاد: گزارش Core Web Vitals تو Search Console و بخش بالای PageSpeed Insights. داده آزمایشگاهی صفحه رو یه بار شبیه سازی می کنه، مثل Lighthouse.

این دو عدد اغلب با هم نمی خونن. Lighthouse معمولاً فقط بارگذاری اولیه رو می بینه و اسکرول نمی کنه. کاربر واقعی اسکرول می کنه، تبلیغ دیرتر لود می شه و تصویر پایین صفحه دیر می رسه. تو ایران یه فاکتور دیگه هم هست: اینترنت موبایل تو ساعت های اوج ترافیک ممکنه کندتر باشه و فونت یا تصویر دیرتر برسه. پس عدد کاربر واقعی ممکنه بدتر از تست خودت باشه.

عنصر مقصر رو پیدا کن

تو Chrome DevTools بخش Performance رو باز کن، صفحه رو رکورد کن و تو ردیف Experience دنبال بلوک های قرمز Layout Shift بگرد. با کلیک روی هر کدوم، عنصری که جابه جا شده نشون داده می شه.

اگه می خوای تو کنسول هم ببینی:

new PerformanceObserver((list) => {
  for (const e of list.getEntries()) {
    if (!e.hadRecentInput) {
      console.log(e.value, e.sources?.map(s => s.node));
    }
  }
}).observe({ type: 'layout-shift', buffered: true });

این کد هر جابه جایی و عناصر درگیرش رو چاپ می کنه. شرط hadRecentInput جابه جایی هایی رو که بعد از ورودی خود کاربر (مثل کلیک) اتفاق افتادن کنار می ذاره، چون CLS اون ها رو حساب نمی کنه.

مقصر معمولاً کیه؟ علت ها به ترتیب احتمال

این ترتیب بر پایه تجربه کار روی سایت های مختلفه. سایت تو ممکنه فرق کنه، ولی از بالا شروع کن.

علتنشانهرفع اصلی
تصویر بدون ابعادمتن بعد از رسیدن تصویر پایین می رهwidth و height یا aspect-ratio
فونت وبعرض و ارتفاع متن بعد از لود فونت عوض می شهfont-display و فونت جایگزین هم اندازه
تبلیغ و ویجتجای خالی یا جهش بعد از لود اسکریپتقاب با min-height
بنر تزریق شده بالای صفحهکل محتوا هل داده می شهموقعیت fixed یا فضای رزرو
محتوای دیررس و انیمیشنلیست یا کارت ها دیر ظاهر می شناسکلت با ارتفاع ثابت و transform

۱. تصویر بدون ابعاد

این شایع ترین علته. مرورگر تا تصویر رو دانلود نکنه، نمی دونه چقدر جا می خواد. تا اون موقع ارتفاعش صفره و بعد یهو باز می شه.

رفعش اینه که ابعاد واقعی رو تو تگ بنویسی:

<img src="/img/product.jpg" width="800" height="600" alt="محصول">
img { max-width: 100%; height: auto; }

مرورگر از روی width و height نسبت تصویر رو حساب می کنه و جاش رو از قبل نگه می داره، حتی اگه CSS بعداً اندازه رو تغییر بده. برای تصویر پس زمینه یا قاب هایی که ابعاد مشخص ندارن، aspect-ratio: 16 / 9 همین کار رو می کنه.

ما تو سیستم خودمون برای این مشکل چاره ای دیدیم: تصاویر آپلودی پهن تر از ۱۶۰۰ پیکسل خودکار کوچک می شن و ابعاد هر تصویر تو صفحه ثبت می شه، تا موقع بارگذاری چیزی جابه جا نشه. اگه سایتت وردپرسی یا فروشگاهی و پر از تصویر محصوله، ابعاد رو دستی هم چک کن.

یه اشتباه رایج: گذاشتن loading="lazy" روی تصویر اصلی بالای صفحه. این کار CLS رو خراب نمی کنه، ولی نمایش اون تصویر رو دیرتر می کنه. lazy فقط برای تصاویری باشه که پایین تر از اولین صفحه نمایش هستن.

۲. فونت وب

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

سه کار به ترتیب:

  1. فونت رو از سرور خودت سرو کن، نه از یه سرویس خارجی. تو ایران دسترسی به سرویس های بین المللی ممکنه کند یا ناپایدار باشه.
  2. فایل woff2 باشه و فقط حروف لازم داخلش باشه (subset).
  3. فونت اصلی رو preload کن:
<link rel="preload" href="/fonts/myfont-subset.woff2" as="font" type="font/woff2" crossorigin>

بعد یه فونت جایگزین تعریف کن که به فونت اصلی نزدیک باشه:

@font-face {
  font-family: "MyFont";
  src: url("/fonts/myfont-subset.woff2") format("woff2");
  font-display: swap;
}
@font-face {
  font-family: "MyFont Fallback";
  src: local("Tahoma");
  size-adjust: 105%;
}
body { font-family: "MyFont", "MyFont Fallback", sans-serif; }

عدد size-adjust فقط نمونه است. باید با فونت خودت تنظیمش کنی تا عرض متن تو دو حالت نزدیک بشه. اگه تغییر فونت اصلاً قابل تحمل نیست، font-display: optional رو امتحان کن. با این گزینه، اگه فونت دیر برسه همون فونت جایگزین می مونه و پرشی نمی بینی. ایرادش اینه که بعضی کاربرها اون بار فونت برندت رو نمی بینن.

۳. تبلیغ، ویجت و محتوای جاسازی شده

تبلیغ معمولاً با اسکریپت میاد و مرورگر قبلش نمی دونه چقدر جا می خواد. همین حرف برای ویدیوی جاسازی شده، نقشه، نظرسنجی و iframe هم صدق می کنه.

قاعده ساده است: جا رو خودت از قبل نگه دار.

.ad-slot { min-height: 250px; }
.video-embed { aspect-ratio: 16 / 9; width: 100%; }

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

سرویس های شخص ثالث دیگه مثل آنالیتیکس معمولاً چیدمان رو نمی پرونن، ولی روی سرعت کلی اثر می ذارن. ما اسکریپت Google Analytics رو بعد از بارگذاری کامل صفحه و تو زمان بیکاری مرورگر لود می کنیم تا کمترین اثر رو روی سرعت داشته باشه.

قاب رزرو شده برای تبلیغ در یک صفحه که محتوای زیرش ثابت می ماند

۴. بنرهایی که بالای صفحه تزریق می شن

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

دو راه داری. یا ارتفاع نوار رو از اول با CSS رزرو کن، یا نوار رو با position: fixed روی صفحه بنشون تا چیزی رو هل نده. اگه نوار قراره بسته بشه، با transform ببندش، نه با تغییر ارتفاع.

۵. محتوای دیررس و انیمیشن

لیست محصولی که با ajax میاد، کامنت هایی که بعد از صفحه لود می شن، یا انیمیشنی که با top، margin یا height حرکت می کنه، همه می تونن جابه جایی بسازن.

برای محتوای دیررس، اسکلت (skeleton) با ارتفاع ثابت بذار. برای انیمیشن از transform و opacity استفاده کن؛ این دو چیدمان رو دوباره حساب نمی کنن و CLS هم نمی سازن.

بعد از رفع پرش چیدمان صفحه، چطور مطمئن بشی؟

تغییر دادی؛ حالا باید ببینی جواب داده.

  1. دوباره Performance رو رکورد کن و ببین بلوک های قرمز رفتن.
  2. با throttling کند (Slow 4G) و کش خالی تست کن. پرش ها تو شرایط کند بیشتر خودشون رو نشون می دن.
  3. تو موبایل واقعی هم نگاه کن، چون اندازه ها و جای تبلیغ ها فرق دارن.
  4. صبر کن. گزارش میدانی Search Console روی داده حدود ۲۸ روز اخیر حساب می شه، پس بهتر شدنش رو فوراً نمی بینی و ممکنه چند هفته طول بکشه.

یه نکته مهم: ممکنه عدد آزمایشگاهی عالی باشه ولی گزارش میدانی هنوز بد باشه. معمولاً یعنی یه الگوی خاص (مثلاً صفحه های محصول یا یه نوع تبلیغ) هنوز می پره. گروه بندی صفحات تو Search Console بهت می گه کدوم دسته مشکل داره.

کاری کن دوباره برنگرده

پرش معمولاً بعد از یه تغییر جدید برمی گرده: یه بنر تازه، یه ویجت نو، یه قالب به روز شده. چند عادت جلوش رو می گیره:

  • هر تصویر جدید رو با ابعاد منتشر کن. اگه سیستمت خودکار این کار رو نمی کنه، تو چک لیست انتشار بنویس.
  • هر ویجت یا اسکریپت جدید رو قبل از انتشار با DevTools تست کن.
  • بعد از به روز کردن قالب و افزونه ها، یه بار صفحه اصلی، محصول و مقاله رو دوباره اندازه بگیر.
  • CLS رو هم کنار بقیه موارد چک لیست سئو فنی سایت؛ از sitemap تا canonical چک کن، نه به عنوان یه کار جدا که یادت بره.

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

سوالات متداول

CLS خوب چه عددیه؟

طبق راهنمای فعلی گوگل، ۰٫۱ یا کمتر «خوب» حساب می شه. این آستانه ممکنه عوض بشه، پس به مستندات web.dev هم نگاه کن. به عدد صفر هم نیازی نیست؛ کمی جابه جایی طبیعیه.

چرا Lighthouse عدد خوب می ده ولی Search Console هشدار CLS می ده؟

Lighthouse فقط بارگذاری اولیه رو تو شرایط شبیه سازی شده می سنجه. Search Console از کاربرهای واقعی با اینترنت، دستگاه و رفتار اسکرول متفاوت داده می گیره. تبلیغ ها یا تصاویری که بعد از اسکرول میان فقط تو داده واقعی دیده می شن.

lazy loading باعث پرش چیدمان می شه؟

خود lazy loading نه، ولی اگه ابعاد تصویر مشخص نباشه، بله. وقتی تصویر پایین صفحه وارد دید می شه و جاش رزرو نشده، محتوای اطرافش جابه جا می شه. با width و height یا aspect-ratio این مشکل برطرف می شه.

آیا جابه جایی بعد از کلیک کاربر هم حساب می شه؟

معمولاً نه. جابه جایی هایی که تا حدود نیم ثانیه بعد از کلیک یا ورودی مستقیم کاربر اتفاق می افتن (مثل باز شدن یه منو) تو CLS حساب نمی شن. ولی تغییر خودکار بدون عمل کاربر حساب می شه.

از کجا شروع کنی؟

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

  • پرش چیدمان صفحه
  • CLS
  • Core Web Vitals
  • سرعت سایت
  • سئو فنی

مقاله‌های مرتبط

ادامه همین موضوع در وبلاگ.

همه مقاله‌ها
کمک فنی

برای اجرای این کار کمک می‌خواهید؟

تیم فنی Wbweb از طراحی سایت تا هاست و سرور کنار شماست؛ درخواستتان را ثبت کنید یا تیکت بزنید.