Responsive Images: قلّل صورة LCP من 1.2MB لـ 180KB
لو صورة الهيرو عندك بتسحب 1.2MB لكل مستخدم، المقال ده هيساعدك تنزل النقل إلى حوالي 180KB للموبايل بدون ما تكسر جودة الصورة.
مستوى القارئ: متوسط
المشكلة باختصار
اللي بيحصل فعلاً إن فريق كتير بيصدّر صورة واحدة كبيرة، مثلاً 2400px JPEG، ويحطها في أعلى الصفحة. على شاشة موبايل عرضها 390px، المتصفح لسه ممكن يحمل نفس الملف الكبير. النتيجة: LCP أعلى، باقة بيانات أكثر، وتجربة أبطأ من غير سبب.
الافتراض هنا إن عندك صفحة تسويق أو صفحة منتج فيها صورة hero فوق الـ fold. عند 50K زيارة يوميًا، فرق 1MB في أول صورة يعني حوالي 50GB نقل زائد كل يوم. لو عندك CDN مدفوع أو مستخدمين على شبكة بطيئة، الرقم ده مش تفصيلة صغيرة.
المثال قبل التعريف
ركز في المثال ده: عندك صورة منتج اسمها hero.jpg حجمها 1.2MB. بدل ما تبعتها لكل الناس، هتطلع منها نسخ 640 و1280 و1920 بامتداد AVIF، ومعاهم WebP كـ fallback. المتصفح يختار النسخة الأنسب حسب عرض الشاشة وكثافة البكسلات.
التعريف العلمي ببساطة: srcset قائمة مرشحين للصورة، وsizes بتقول للمتصفح الصورة هتاخد عرض قد إيه في layout. عنصر picture يضيف اختيار format، مثل AVIF أولاً ثم WebP ثم JPEG. أفضل طريقة هنا إنك تدي المتصفح معلومات كفاية، بدل ما تجبره يحمل أكبر ملف.
جهّز الصور بسطرين
استخدم Sharp في build step. ده مناسب لو الصور عندك ضمن المشروع أو بتتولد قبل النشر. المكسب: ملفات أصغر واختيار ذكي في المتصفح. التكلفة: وقت build أطول ومجلد assets فيه نسخ أكثر.
npm install sharp
mkdir -p public/img
node scripts/build-hero-images.mjs
// scripts/build-hero-images.mjs
import sharp from 'sharp';
const input = 'assets/hero.jpg';
const widths = [640, 1280, 1920];
for (const width of widths) {
await sharp(input)
.resize({ width, withoutEnlargement: true })
.avif({ quality: 55 })
.toFile(`public/img/hero-${width}.avif`);
await sharp(input)
.resize({ width, withoutEnlargement: true })
.webp({ quality: 72 })
.toFile(`public/img/hero-${width}.webp`);
}
استخدم picture/srcset صح
الكود المهم في الصفحة نفسها. لا تكتب srcset من غير لو الصورة responsive، لأن المتصفح وقتها هيخمن، وغالبًا هيختار ملف أكبر من اللازم.