اجازه بدهید این مفاهیم را با یک تشبیه ساده شروع کنم. فرض کنید کاربر وارد یک رستوران (وبسایت) میشود:
این معیار زمان بارگذاری بزرگترین المان قابل مشاهده در صفحه را اندازه میگیرد. مثل این میماند که مشتری تا کی باید منتظر بماند تا غذای اصلی اش روی میز بیاید. در یک وبسایت، این المان معمولا تصویر اصلی (Hero Image) یا عنوان بزرگ است. استاندارد خوب یعنی زیر ۲.۵ ثانیه. اگر بالاتر باشد، کاربر حس میکند سایت کند است.
این معیار فاصله زمانی بین اولین تعامل کاربر (مثلا کلیک روی دکمه) تا زمانی که مرورگر بتواند به آن واکنش نشان دهد را اندازه میگیرد. مثل این است که مشتری به پیشخدمت علامت میدهد اما پیشخدمت چند ثانیه طول میکشد تا متوجه شود و پاسخ دهد. استاندارد خوب زیر ۱۰۰ میلی ثانیه است. این معیار نشان میدهد که مرورگر چقدر مشغول پردازش کارهای سنگین است.
این معیار میزان جابجایی غیرمنتظره المانهای صفحه را اندازه میگیرد. فرض کنید مشتری میخواهد دکمه سفارش را بزند اما ناگهان یک بنر تبلیغاتی پایین میآید و دکمه جابجا میشود و مشتری روی چیز دیگری کلیک میکند. استاندارد خوب زیر ۰.۱ است.
این معیار نشان میدهد صفحه از چه زمانی کاملا آماده تعامل با کاربر است. یعنی هم محتوا نشان داده شده و هم event listener ها متصل شدهاند و کاربر میتواند با همه المانها کار کند. استاندارد خوب زیر ۵ ثانیه است.
این معیار مجموع زمانی است که صفحه به دلیل پردازشهای سنگین جاوااسکریپت، قادر به پاسخگویی به ورودیهای کاربر نیست. هر بخش از پردازش که بیش از ۵۰ میلی ثانیه طول بکشد، به عنوان زمان مسدودیت محسوب میشود. استاندارد خوب زیر ۳۰۰ میلی ثانیه است.
فرض کنید مدیر محصول به شما میگوید که LCP سایت ما ۴ ثانیه است و CLS هم ۰.۲۵ است. راهحل شما چیست؟
۱. از Image کامپوننت Next.js با priority استفاده کنید تا تصاویر اصلی زودتر بارگذاری شوند
۲. از SSR یا ISR به جای CSR برای صفحات اصلی استفاده کنید
۳. فایلهای جاوااسکریپت را با dynamic import به بخشهای کوچک تقسیم کنید
۴. از CDN برای بارگذاری assets استفاده کنید
۱. کدهای سنگین را با استفاده از Web Workers به ترد جداگانه ببرید
۲. از useDeferredValue و useTransition در React برای اولویتبندی رندرها استفاده کنید
۳. اجرای کدهای غیرضروری را به بعد از بارگذاری صفحه موکول کنید (با useEffect و setTimeout)
۱. برای همه تصاویر و ویدیوها، width و height مشخص کنید
۲. از placeholder های skeleton استفاده کنید تا فضای المانها قبل از بارگذاری مشخص باشد
۳. از font-display: optional برای فونتها استفاده کنید تا متن با فونت سیستمی نشان داده شود و بعدا جایگزین شود
jsx
// بهبود LCP با اولویت تصویر import Image from 'next/image' <Image src="/hero.jpg" priority // این باعث میشود تصویر زودتر بارگذاری شود width={1200} height={600} placeholder="blur" // کاهش CLS /> // بهبود TTI با dynamic import const HeavyComponent = dynamic(() => import('./HeavyComponent'), { loading: () => <Skeleton />, ssr: false // اگر نیازی به SSR نداشته باشد }) // بهبود FID با useTransition const [isPending, startTransition] = useTransition() const handleSearch = (value) => { startTransition(() => { setSearchResults(filterData(value)) // این عملیات سنگین را به اولویت پایینتر میدهد }) }
نکته مهم این است که این معیارها به هم وابسته هستند. مثلا اگر TBT بالا باشد، FID هم بد میشود چون مرورگر مشغول است. یا اگر تصاویر با اندازه مشخص نباشند، CLS بالا میرود.
در نهایت برای اندازهگیری این معیارها از ابزارهای زیر استفاده میکنیم:
Lighthouse در DevTools
Core Web Vitals گزارش شده در Google Search Console
کتابخانه web-vitals در Next.js که میتواند دادههای واقعی کاربران را جمعآوری کند