النطاق: هذا مرجع تنفيذ عملي. راجع توثيق Google والمنصات الحالية قبل اتخاذ قرار إصدار أو سياسة.
ابدأ بالـtrace الصحيح
قس الصفحة نفسها في ثلاثة أماكن: Search Console وCrUX لتوزيع field data، وPageSpeed Insights لسياق المختبر والميدان، وChrome Performance trace مع throttling لمعرفة السبب. سجّل نوع الجهاز والاتصال والـrelease SHA وعنصر LCP. لا تقارن p75 للموبايل بدرجة Lighthouse على desktop.
# تسجيل trace قابل للتكرار
npx lighthouse https://example.com/landing \
--preset=desktop --throttling-method=simulate \
--output=json --output-path=./artifacts/lighthouse.json
# استخراج عنصر LCP والمهام الطويلة
jq '.audits["largest-contentful-paint-element"], .audits["long-tasks"]' \
./artifacts/lighthouse.json- افتح DevTools Performance وفَعّل Screenshots وWeb Vitals، ثم سجّل تحميلًا باردًا على إعداد موبايل.
- افحص علامة LCP وحدد هل العنصر صورة أم نص أم background.
- رتب Network حسب بداية الـwaterfall؛ خط أو script متأخر قد يؤخر الرسم حتى لو الصورة cached.
- كرر الاختبار مع cache معطل ثم دافئًا، وسجّل الفرق.
اختناقات Next.js App Router
يمكن للصفحة أن تكون static-generated ومع ذلك تخسر LCP بسبب client hydration. اترك الـhero والنص الحرج داخل Server Component، وانقل التفاعل فقط إلى client island صغير. لا تستورد animation أو analytics ثقيلًا داخل شجرة الـhero.
// app/(en)/landing/page.tsx
import Image from 'next/image'
export default function LandingPage() {
return (
<main>
<section className="hero">
<h1>Technical SEO systems that survive production</h1>
<Image src="/hero.avif" alt="" width={1440} height={900}
priority sizes="(max-width: 768px) 100vw, 720px" />
</section>
<InteractiveFilters />
</main>
)
}إذا كان LCP نصًا، حمّل الخط المستخدم فعلًا فقط. وإذا كان صورة، فـpriority وsizes الصحيحة أهم من preload عام. لا تعمل preload لنسخة desktop ونسخة mobile معًا.
الخطوط والسكريبتات الخارجية
CSS غير محسّن للخطوط قد يجعل text LCP يتأخر أو يسبب layout ثانيًا. استخدم next/font مع display: swap وfallback واقعي، ولا تعمل preload إلا للعائلات الموجودة فوق الـfold. السكريبتات الخارجية لا يجب أن تدخل المسار الحرج.
// lib/fonts.ts
import { Inter, Cairo } from 'next/font/google'
export const body = Inter({
subsets: ['latin'], display: 'swap', preload: true,
fallback: ['Arial', 'sans-serif'], variable: '--font-body',
})
// Analytics: afterInteractive; ads/chat: lazyOnload
<Script src={analyticsUrl} strategy="afterInteractive" />
<Script src={adsUrl} strategy="lazyOnload" />في trace ابحث عن long tasks خلال أول 2.5 ثانية. consent manager أو tag manager أو chat bootstrap مدته 180ms قد يؤخر الإطار الذي يحتوي عنصر LCP. أخره إلى ما بعد التفاعل أو أزل اعتماده من route الأول.
تحولات التخطيط الخفية
غالبًا يشترك CLS وLCP في السبب نفسه: المتصفح لا يستطيع تثبيت التخطيط لأن الأبعاد غير معروفة. احجز مساحة للصورة والإعلان والـembed، ولا تحقن banner فوق محتوى موجود بعد أول paint.
/* احجز مساحة الوسائط قبل اكتمال الطلب */
.hero-media { aspect-ratio: 16 / 10; }
.ad-slot { min-height: 280px; }
.hero img { display: block; width: 100%; height: auto; }الاختبار النهائي ميداني: قارن CrUX p75 بعد وصول زيارات جديدة كافية لنفس مجموعة URLs. إصلاح المختبر فرضية، أما p75 الميداني فهو قرار الإصدار.