Core Web Vitals چیست؟ راهنمای کامل بهبود LCP، INP و CLS
Core Web Vitals چیست و چرا برای سئو و تجربه کاربری مهم است؟ راهنمای عملی سنجش و بهبود LCP، INP و CLS با کد و چکلیست برای توسعهدهندگان وب.

فهرست مطالب
Core Web Vitals مجموعهای از سه شاخص است که گوگل برای سنجش تجربه واقعی کاربران از یک صفحه وب تعریف کرده است: سرعت نمایش محتوای اصلی، سرعت پاسخ به تعامل و پایداری بصری صفحه. این شاخصها هم بخشی از سیگنالهای رتبهبندی گوگل هستند و هم مستقیماً روی نرخ تبدیل و ماندگاری کاربر اثر میگذارند.
در این راهنما یاد میگیریم هر شاخص دقیقاً چه چیزی را میسنجد، چطور اندازهاش بگیریم و با چه تکنیکهایی بهترش کنیم.
Core Web Vitals چیست و چه شاخصهایی دارد؟
طبق مستندات web.dev، سه شاخص اصلی و آستانههای آنها اینهاست:
| شاخص | چه چیزی را میسنجد | خوب | نیاز به بهبود | ضعیف |
|---|---|---|---|---|
| LCP (Largest Contentful Paint) | زمان نمایش بزرگترین محتوای قابل مشاهده | تا ۲٫۵ ثانیه | تا ۴ ثانیه | بیش از ۴ ثانیه |
| INP (Interaction to Next Paint) | تأخیر پاسخ صفحه به تعاملهای کاربر | تا ۲۰۰ میلیثانیه | تا ۵۰۰ میلیثانیه | بیش از ۵۰۰ میلیثانیه |
| CLS (Cumulative Layout Shift) | میزان جابهجایی ناخواسته عناصر صفحه | تا ۰٫۱ | تا ۰٫۲۵ | بیش از ۰٫۲۵ |
یک نکته کلیدی: گوگل این اعداد را در صدک ۷۵ام بازدیدهای واقعی و جداگانه برای موبایل و دسکتاپ میسنجد. یعنی اگر ۷۵ درصد بازدیدها تجربه خوبی داشته باشند، صفحه در آن شاخص «خوب» حساب میشود.
داده میدانی در برابر داده آزمایشگاهی
پیش از بهینهسازی باید بدانید با چه دادهای کار میکنید:
- داده میدانی (Field Data): از کاربران واقعی جمع میشود. گزارش تجربه کاربری کروم (CrUX)، گزارش Core Web Vitals در Search Console و بخش بالایی PageSpeed Insights از این نوعاند. ملاک ارزیابی گوگل همین داده است.
- داده آزمایشگاهی (Lab Data): در محیطی کنترلشده، مثلاً با Lighthouse یا تب Performance در DevTools، تولید میشود. برای عیبیابی عالی است، اما کاربر واقعی نیست.
INP به تعامل واقعی کاربر نیاز دارد، پس Lighthouse مستقیم آن را گزارش نمیکند. در آزمایشگاه، شاخص Total Blocking Time (TBT) نشانه خوبی از مشکلات احتمالی INP است.
سنجش Core Web Vitals با کتابخانه web-vitals
بهترین راه این است که شاخصها را از کاربران خودتان جمع کنید. کتابخانه رسمی web-vitals گوگل این کار را ساده میکند:
npm install web-vitals
import { onCLS, onINP, onLCP } from "web-vitals";
function sendToAnalytics(metric) {
const body = JSON.stringify({
name: metric.name,
value: metric.value,
rating: metric.rating, // "good" | "needs-improvement" | "poor"
id: metric.id,
});
if (!navigator.sendBeacon?.("/analytics", body)) {
fetch("/analytics", { body, method: "POST", keepalive: true });
}
}
onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);
هر تابع را فقط یک بار در هر بارگذاری صفحه صدا بزنید. برای پیدا کردن علت مشکل، نسخه web-vitals/attribution اطلاعات بیشتری مثل عنصر LCP یا اسکریپت مسئول تعامل کند را هم برمیگرداند.
بهبود LCP: محتوای اصلی را زودتر نشان دهید
در بیشتر سایتها عنصر LCP یک تصویر بزرگ، مثل تصویر شاخص مقاله یا بنر صفحه اول، یا یک بلوک متن بزرگ است. زمان LCP از چهار بخش تشکیل میشود: زمان پاسخ سرور (TTFB)، تأخیر شروع دانلود منبع، مدت دانلود آن و تأخیر رندر عنصر. برای بهبودش:
۱. تصویر LCP را زود و با اولویت بالا دانلود کنید. مرورگر باید تصویر را در همان HTML اولیه پیدا کند، نه بعد از اجرای جاوااسکریپت:
<img
src="/images/hero.avif"
alt="Hero image"
width="1200"
height="675"
fetchpriority="high"
/>
۲. تصویر LCP را هرگز lazy-load نکنید. ویژگی loading="lazy" برای تصاویر پایین صفحه عالی است، اما روی تصویر بالای صفحه دانلودش را عقب میاندازد.
۳. اگر تصویر در CSS تعریف شده، آن را preload کنید:
<link rel="preload" as="image" href="/images/hero.avif" fetchpriority="high" />
۴. TTFB را پایین بیاورید. کش سمت سرور، CDN و رندر ایستا برای صفحههایی که زیاد تغییر نمیکنند، بیشترین اثر را دارند.
۵. فرمت و اندازه درست. از AVIF یا WebP و از srcset استفاده کنید تا موبایل تصویر ۴K دانلود نکند.
بهبود INP: رشته اصلی را آزاد نگه دارید
INP زمانی بد میشود که کاربر کلیک میکند اما مرورگر مشغول اجرای جاوااسکریپت است و نمیتواند فریم بعدی را رسم کند. هر کاری که بیش از ۵۰ میلیثانیه رشته اصلی (Main Thread) را اشغال کند، یک تسک طولانی (Long Task) است و دشمن اصلی INP به حساب میآید.
راهحل اصلی، شکستن کارهای سنگین و واگذاری کنترل به رشته اصلی (Yielding) است. API جدید scheduler.yield() برای همین طراحی شده، اما هنوز در همه مرورگرها پشتیبانی نمیشود؛ پس یک جایگزین هم میگذاریم:
function yieldToMain() {
if (globalThis.scheduler?.yield) {
return scheduler.yield();
}
return new Promise((resolve) => setTimeout(resolve, 0));
}
async function processItems(items) {
let lastYield = performance.now();
for (const item of items) {
heavyWork(item);
// Yield roughly every 50ms so the browser can respond to input
if (performance.now() - lastYield > 50) {
await yieldToMain();
lastYield = performance.now();
}
}
}
چند توصیه دیگر برای INP:
- بازخورد فوری بدهید. اول رابط کاربری را بهروز کنید (مثلاً نمایش حالت بارگذاری) و کار سنگین را بعد از آن انجام دهید.
- جاوااسکریپت کمتر بفرستید. اسکریپتهای شخص ثالث، مثل ابزارهای تحلیل و چت آنلاین، را بازبینی کنید و آنهایی را که لازم نیست حذف یا با تأخیر بارگذاری کنید.
- DOM را کوچک نگه دارید. صفحهای با دهها هزار گره، هر بهروزرسانی را کند میکند.
- در فریمورکها، کد سمت کلاینت را محدود کنید. در Next.js این یعنی استفاده حداکثری از Server Components؛ در آموزش Next.js App Router این الگو را عملی دیدهایم.
بهبود CLS: جای هر چیز را از قبل رزرو کنید
CLS وقتی بالا میرود که عناصر بعد از نمایش، جابهجا شوند؛ مثلاً میخواهید روی لینکی بزنید و ناگهان یک بنر تبلیغاتی بالای آن ظاهر میشود. مهمترین راهحلها:
۱. برای تصاویر و ویدیوها ابعاد مشخص کنید. با ویژگیهای width و height، مرورگر پیش از دانلود، نسبت تصویر را میداند و فضا را رزرو میکند. برای عناصر واکنشگرا هم از aspect-ratio استفاده کنید:
img,
video {
max-width: 100%;
height: auto;
}
.embed-container {
aspect-ratio: 16 / 9;
width: 100%;
}
.ad-slot {
min-height: 250px; /* reserve space before the ad loads */
}
۲. محتوای پویا را بالای محتوای موجود تزریق نکنید، مگر در پاسخ به تعامل کاربر.
۳. فونتها را کنترل کنید. تعویض فونت جایگزین با فونت وب میتواند متن را جابهجا کند. فونت اصلی را preload کنید و با size-adjust ابعاد فونت جایگزین را به فونت اصلی نزدیک کنید:
@font-face {
font-family: "Vazirmatn";
src: url("/fonts/vazirmatn.woff2") format("woff2");
font-display: swap;
}
@font-face {
font-family: "Vazirmatn Fallback";
src: local("Tahoma");
size-adjust: 105%;
}
body {
font-family: "Vazirmatn", "Vazirmatn Fallback", sans-serif;
}
مقدار size-adjust را برای فونت خودتان با آزمون و مقایسه پیدا کنید؛ عدد بالا فقط یک نمونه است.
۴. انیمیشنها را با transform بسازید. تغییر top یا height باعث چیدمان مجدد و جابهجایی میشود، اما transform نه.
چکلیست سریع بهینهسازی Core Web Vitals
- داده میدانی را از Search Console یا PageSpeed Insights بررسی کنید.
- کتابخانه
web-vitalsرا برای سنجش کاربران واقعی نصب کنید. - تصویر LCP را با
fetchpriority="high"و بدون lazy-load بارگذاری کنید. - TTFB را با کش و CDN کاهش دهید.
- تسکهای طولانی را در DevTools پیدا و خرد کنید.
- اسکریپتهای شخص ثالث غیرضروری را حذف کنید.
- برای همه تصاویر، ویدیوها و جایگاههای تبلیغ فضا رزرو کنید.
- بارگذاری فونتها را بهینه کنید.
جمعبندی
Core Web Vitals سه سؤال ساده را از زاویه کاربر میپرسد: محتوا کی ظاهر شد؟ صفحه به کلیکم سریع جواب داد؟ چیزی زیر دستم جابهجا نشد؟ اگر به این سه سؤال پاسخ خوبی بدهید، هم کاربران راضیترند و هم گوگل.
یادتان باشد تغییرات در داده میدانی با تأخیر دیده میشوند، چون CrUX بر اساس بازهای ۲۸ روزه محاسبه میشود. پس بعد از هر بهینهسازی صبور باشید و روند را دنبال کنید.



