next/image لن يصلح لك الـ LCP
المكوّن يحسّن البايتات. أما الـ LCP فيحدّده وقت بدء الطلب، وأسبابه المعتادة ترتيب الاكتشاف، وصورة بطل مؤجّلة التحميل، وخطّ يحجب الرسم.
تصلنا فرقٌ استبدلت كل <img> بـnext/image سلفًا، ولم يتحرّك الـ LCP. وهذه
هي النتيجة المتوقّعة، ويستحقّ فهم السبب، لأن المنطق نفسه يشير إلى ما كان
سينفع فعلًا.
يحسّن next/image الحمولة: صيغة أصغر، وأبعاد مناسبة للجهاز، وبلا إزاحة
تخطيط. أما الـ LCP فيقيس توقيت أكبر رسم. البايتات أحد مدخلات ذلك، وليست
المدخل الحاكم عادةً.
ما الذي يحدّد وقت بدء الطلب
لا يستطيع المتصفّح جلب إلا ما اكتشفه. ولصورة البطل ثلاثة احتمالات، بينها فرق بمقدار رتبة كاملة:
| كيف تُكتشَف الصورة | متى يبدأ الطلب |
|---|---|
<img> في HTML الأولي، فوري | أثناء مسح التحميل المسبق، قبل الـ CSS |
<img> في HTML الأولي، مؤجّل | بعد التخطيط، حين يعلم المتصفّح أنها ظاهرة |
| مُدرَجة بجافاسكريبت بعد الترطيب | بعد تنزيل الحزمة وتحليلها وتشغيلها |
وnext/image يؤجّل التحميل افتراضيًا. فالترحيل الشائع يحوّل صورة بطل
فورية إلى مؤجّلة، ويؤخّر طلبها إلى ما بعد التخطيط، ويزيد الـ LCP سوءًا - بينما
تخضرّ كل تدقيقات الصور في Lighthouse.
العلاج خاصيّة واحدة:
import Image from 'next/image';
export function Hero() {
return (
<Image
src="/hero.jpg"
alt="..."
width={1600}
height={900}
priority // فوري + fetchpriority="high" + تلميح تحميل مسبق
sizes="100vw"
className="w-full h-auto"
/>
);
}priority على صورة واحدة بالضبط في كل مسار - تلك التي هي عنصر الـ LCP. ووضعها
على ستّ صور يعادل عدم وضعها إطلاقًا، لأن الجميع يتنافس على الاتصال نفسه.
خطأ sizes الذي يكلّف أكثر من الصيغة
تخبر sizes المتصفّح أي مرشّح يختار من srcset، وتُقيَّم قبل التخطيط.
أخطئ فيها فتنزّل صورة بعرض 1600 بكسل لموضع عرضه 400 - أو، وهو أسوأ للجودة،
صورة بعرض 400 بكسل للافتة تملأ العرض.
الافتراضي عند إغفالها هو 100vw، وهو صحيح لصورة بطل بعرض كامل وخاطئ لكل ما
عداها:
// صورة بطاقة داخل شبكة من ثلاثة أعمدة.
<Image
src={post.cover}
alt=""
width={800}
height={450}
sizes="(min-width: 1024px) 33vw, (min-width: 640px) 50vw, 100vw"
/>هذه السمة وحدها تساوي عادةً أكثر من التحويل إلى AVIF، لأنها تغيّر أي ملفّ يُطلَب لا كم بايتًا في ذلك الملفّ.
حين يكون عنصر الـ LCP نصًّا
في موقع محتوى يكون كذلك غالبًا، وعندها يصبح العمل على الصور في غير محلّه. فالعنوان لا يُرسَم قبل تسوية خطّه، والسلسلة إذن: HTML ← CSS ← ملفّ الخط ← رسم.
import { Inter } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap', // ارسم بالخط الاحتياطي وبدّل حين يصل الملف
variable: '--font-sans',
});يستضيف next/font الملفّ ذاتيًا ويصدر تحميلًا مسبقًا، فيُخرج اتصال الطرف
الثالث من السلسلة. وdisplay: 'swap' هي ما يمنع العنوان من الانتظار أصلًا -
وثمنها تبديل مرئي، تقلّله باختيار خط احتياطي بمقاييس مقاربة لا بحجب الرسم.
النصف الآخر هو قائمة الخطوط الاحتياطية.
font-family: var(--font-sans), sans-serif يجعل المتصفّح يرسم فورًا بخطٍّ لم
تختر مقاييسه؛ أما تسمية خط نظام قريب فتجعل التبديل أقلّ لفتًا بكثير.
قياس الشيء الصحيح
يبلّغ Lighthouse عن LCP مخبري في تحميل بارد ومقيَّد. وتبلّغ بيانات الميدان عمّا عاشه زوّارك فعلًا، بما فيه إصابات الذاكرة المؤقّتة والأجهزة الحقيقية. والاثنان يتعارضان باستمرار، ورقم الميدان هو المعتبر.
'use client';
import { useReportWebVitals } from 'next/web-vitals';
export function Vitals() {
useReportWebVitals((metric) => {
if (metric.name !== 'LCP') return;
// العنصر لا الرقم وحده - «الـ LCP 3.1 ثانية» لا يُبنى عليه عمل،
// أما «الـ LCP 3.1 ثانية وهو صورة البطل» فيُبنى عليه.
navigator.sendBeacon('/api/vitals', JSON.stringify({
value: metric.value,
element: metric.attribution?.element,
url: location.pathname,
}));
});
return null;
}سجّل العنصر. نصف مشاريع الأداء التي ننفّذها تبدأ باكتشاف أن عنصر الـ LCP ليس
ما افترضه الفريق - لافتة ملفّات تعريف الارتباط، أو <h1> مخفي، أو حاوية فارغة
تصادف أنها كبيرة.
الترتيب الكامل لما يُصلَح وبأي تسلسل موجود في مؤشرات Core Web Vitals في Next.js: ما الذي يحرّك الأرقام فعلًا.
النسخة المختصرة
- اعرف أي عنصر هو الـ LCP، من بيانات الميدان، لكل مسار على حدة.
- إن كان صورة:
priorityعلى تلك الصورة وحدها، وsizesصحيحة، وتأكّد ألّا يحجب المحلّل شيءٌ فوقها في الـ HTML. - إن كان نصًّا:
next/fontمعdisplay: 'swap'وخط احتياطي بمقاييس قريبة. - وبعد ذلك فقط فكّر في الصيغة والجودة.
الثواني في الخطوات من واحد إلى ثلاثة. والتدقيقات في الخطوة الرابعة - ولهذا تحديدًا هي التي تُنفَّذ أولًا.
