رفتن به محتوای اصلی

قسمت ۱۰ – تصاویر ریسپانسیو با picture، srcset و lazy loading

  • سینا قربانیان
  • ۱۷ آبان ۱۴۰۵
  • ۱۱ دقیقه مطالعه
  • ۰ بازدید
آموزش تگ picture در html و srcset برای تصاویر ریسپانسیو
فهرست مطالب
  1. تصاویر ریسپانسیو چیست و چرا یک تصویر برای همه کافی نیست؟
  2. srcset در html چیست و چطور کار می‌کند؟
  3. توصیف‌گر x برای تصاویر با اندازه ثابت
  4. sizes در html چه کاری انجام می‌دهد؟
  5. تگ picture در html چه زمانی لازم است؟
  6. ارائه AVIF و WebP با جایگزین
  7. هدایت هنری (Art Direction) با media
  8. lazy load تصاویر در HTML چطور انجام می‌شود؟
  9. sizes=”auto” برای تصاویر lazy
  10. lazy loading برای iframe
  11. srcset یا picture؛ کدام را انتخاب کنیم؟
  12. از تجربه تیم siloow: تصاویر ریسپانسیو در وردپرس
  13. اشتباهات رایج در تصاویر ریسپانسیو
  14. محدودیت‌ها و چه زمانی ساده بمانیم؟
  15. تمرین این قسمت
  16. جمع‌بندی و خلاصه
  17. منابع
  18. سوالات متداول درباره تگ picture در html
  19. تفاوت تگ picture و srcset چیست؟
  20. alt را در تگ picture کجا بنویسم؟
  21. آیا برای lazy load تصاویر هنوز به جاوااسکریپت نیاز است؟
  22. اگر sizes را ننویسم چه می‌شود؟
  23. وردپرس srcset را خودکار می‌سازد؛ باز هم باید کاری کنم؟

تگ picture در html ظرفی است که چند منبع تصویر (<source>) و یک <img> جایگزین را در خود نگه می‌دارد تا مرورگر بر اساس فرمت پشتیبانی‌شده، اندازه صفحه یا تنظیمات کاربر بهترین تصویر را انتخاب کند. در کنار آن، اتریبیوت‌های srcset و sizes روی خود img و loading="lazy" سه ابزار اصلی ساخت تصاویر ریسپانسیو در HTML هستند.

نویسنده: تیم siloow (سیلو سولوشن) — آخرین به‌روزرسانی: آبان ۱۴۰۵

در این قسمت یاد می‌گیرید چه زمانی srcset کافی است و چه زمانی به picture نیاز دارید، sizes را چطور بنویسید که مرورگر تصویر درست را دانلود کند، فرمت‌های AVIF و WebP را با جایگزین امن ارائه دهید و lazy load تصاویر را بدون آسیب به سرعت صفحه پیاده کنید. پیش‌نیاز این قسمت، قسمت ۹: درج تصویر با تگ img و متن alt است.

تصاویر ریسپانسیو چیست و چرا یک تصویر برای همه کافی نیست؟

تصاویر ریسپانسیو یعنی صفحه برای هر دستگاه، نسخه‌ای از تصویر را بفرستد که با اندازه نمایش، تراکم پیکسل صفحه و فرمت‌های پشتیبانی‌شده آن دستگاه متناسب است. اگر یک تصویر ۱۶۰۰ پیکسلی را برای گوشی‌ای بفرستید که آن را در ۳۶۰ پیکسل نمایش می‌دهد، کاربر چند برابر حجم لازم را دانلود کرده است.

دو مسئله متفاوت داریم که راه‌حل متفاوتی دارند. مسئله اول «انتخاب وضوح» (Resolution Switching) است: همان تصویر، فقط در اندازه‌های مختلف؛ این کار با srcset و sizes انجام می‌شود. مسئله دوم «هدایت هنری» (Art Direction) است: تصویر متفاوت یا برش متفاوت برای صفحه‌های مختلف، یا فرمت متفاوت؛ این کار تگ picture است. راهنمای تصاویر ریسپانسیو MDN دقیقاً همین تفکیک را توضیح می‌دهد.

مقایسه انتخاب وضوح با srcset و هدایت هنری با تگ picture در html
دو مسئله متفاوت در تصاویر ریسپانسیو

srcset در html چیست و چطور کار می‌کند؟

srcset در html فهرستی از نسخه‌های مختلف یک تصویر به همراه عرض واقعی هر نسخه (توصیف‌گر w) یا تراکم پیکسل آن (توصیف‌گر x) است؛ مرورگر با توجه به عرض صفحه، تراکم پیکسل و حتی سرعت اینترنت، یکی از این نسخه‌ها را انتخاب و فقط همان را دانلود می‌کند.

<!-- نسخه‌های مختلف یک عکس با عرض‌های متفاوت -->
<img
src="cake-800.webp"
srcset="cake-400.webp 400w,
cake-800.webp 800w,
cake-1200.webp 1200w,
cake-1600.webp 1600w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="کیک شکلاتی با روکش گاناش و توت‌فرنگی تازه"
width="1600" height="1067">

عدد کنار w باید دقیقاً عرض واقعی فایل به پیکسل باشد، نه عرضی که دوست دارید نمایش داده شود. اتریبیوت src هم همچنان لازم است؛ مرورگرهای خیلی قدیمی که srcset را نمی‌شناسند از آن استفاده می‌کنند. width و height را برابر با ابعاد بزرگ‌ترین نسخه (یا هر نسخه با همان نسبت ابعاد) بنویسید تا فضای تصویر رزرو شود.

توصیف‌گر x برای تصاویر با اندازه ثابت

وقتی تصویر همیشه در یک اندازه ثابت نمایش داده می‌شود (مثل لوگو یا آواتار)، فقط تراکم پیکسل صفحه فرق می‌کند. در این حالت از توصیف‌گر x استفاده کنید و sizes لازم نیست:

<!-- لوگو با اندازه ثابت؛ فقط تراکم پیکسل فرق می‌کند -->
<img
src="logo.png"
srcset="logo.png 1x, logo@2x.png 2x, logo@3x.png 3x"
alt="صفحه اصلی کافه نمونه"
width="160" height="48">

طبق مستندات MDN درباره img، ترکیب توصیف‌گر w و x در یک srcset نادرست است؛ برای هر تصویر یکی را انتخاب کنید.

sizes در html چه کاری انجام می‌دهد؟

sizes در html به مرورگر می‌گوید تصویر در هر اندازه صفحه تقریباً چه عرضی در طرح‌بندی خواهد داشت؛ مرورگر این عرض را با srcset ترکیب می‌کند تا کوچک‌ترین نسخه کافی را انتخاب کند. sizes فقط وقتی معنا دارد که srcset توصیف‌گر w داشته باشد.

مشکل این است که مرورگر قبل از دانلود CSS باید تصمیم بگیرد کدام تصویر را دانلود کند؛ پس از CSS خبر ندارد و شما با sizes این اطلاعات را به او می‌دهید. sizes فهرستی از شرط‌های مدیا و عرض‌هاست که مرورگر اولین شرط درست را انتخاب می‌کند؛ آخرین مقدار بدون شرط، حالت پیش‌فرض است. اگر sizes را ننویسید، مقدار پیش‌فرض آن 100vw (تمام عرض صفحه) است و مرورگر ممکن است تصویری بزرگ‌تر از نیاز دانلود کند.

<!-- در صفحه‌های تا ۶۰۰ پیکسل: تمام عرض -->
<!-- تا ۱۰۰۰ پیکسل: نصف عرض -->
<!-- بزرگ‌تر: یک‌سوم عرض منهای فاصله‌ها -->
sizes="(max-width: 600px) 100vw,
(max-width: 1000px) 50vw,
calc(33vw - 2rem)"

نکته: لازم نیست sizes کاملاً دقیق باشد؛ یک تخمین نزدیک به عرض واقعی کافی است. اما اگر بعداً طرح‌بندی را در CSS عوض کردید (مثلاً کارت‌ها از دو ستون به سه ستون رفتند)، sizes را هم به‌روز کنید؛ وگرنه مرورگر تصویر بزرگ‌تر از لازم دانلود می‌کند.

تگ picture در html چه زمانی لازم است؟

تگ picture در html وقتی لازم است که بخواهید فرمت‌های مدرن مثل AVIF را با جایگزین امن ارائه دهید، یا برای صفحه‌های مختلف تصویر یا برش کاملاً متفاوتی نمایش دهید. picture به‌تنهایی چیزی نمایش نمی‌دهد؛ همیشه باید یک <img> به‌عنوان آخرین فرزند داشته باشد و alt، width و height روی همان img نوشته می‌شود.

ارائه AVIF و WebP با جایگزین

مرورگر sourceها را به ترتیب بررسی می‌کند و اولین source که نوع (type) آن را پشتیبانی کند انتخاب می‌کند؛ اگر هیچ‌کدام پشتیبانی نشد، تصویر src خود img بارگذاری می‌شود. پس ترتیب مهم است: فشرده‌ترین فرمت اول.

<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg"
alt="ویترین شیرینی‌فروشی با کیک‌ها و دسرهای رنگارنگ"
width="1600" height="900">
</picture>

هدایت هنری (Art Direction) با media

بنری که در دسکتاپ افقی و پر از جزئیات است، در موبایل کوچک و ناخوانا می‌شود. با اتریبیوت media روی source می‌توانید برای موبایل تصویر عمودی یا برش‌خورده روی سوژه اصلی بفرستید. اتریبیوت‌های width و height روی source هم مجاز است تا نسبت ابعاد هر نسخه جداگانه مشخص شود:

<picture>
<!-- موبایل: تصویر عمودی و برش‌خورده روی محصول -->
<source media="(max-width: 600px)"
srcset="banner-mobile.webp"
width="600" height="800">
<!-- دسکتاپ: تصویر افقی کامل -->
<img src="banner-desktop.webp"
alt="جشنواره پاییزی کافه؛ ۲۰ درصد تخفیف نوشیدنی‌های گرم"
width="1600" height="600">
</picture>

یک کاربرد جالب دیگر، لوگوی متفاوت برای حالت تاریک سیستم‌عامل است:

<picture>
<source media="(prefers-color-scheme: dark)"
srcset="logo-dark.svg">
<img src="logo-light.svg" alt="سیلو سولوشن"
width="160" height="48">
</picture>
المان / اتریبیوترویکارنکته
<picture>–ظرف منابع جایگزینخودش چیزی نمایش نمی‌دهد
<source>pictureیک منبع کاندیدبه ترتیب بررسی می‌شود
srcsetimg و sourceفهرست نسخه‌ها با w یا xw باید عرض واقعی فایل باشد
sizesimg و sourceعرض نمایش تخمینیپیش‌فرض 100vw؛ فقط با w
typesourceنوع MIME فرمتimage/avif، image/webp
mediasourceشرط مدیا کوئریبرای Art Direction
loadingimg و iframeبارگذاری تنبل یا فوریlazy / eager
fetchpriorityimgاولویت دانلودhigh برای تصویر LCP
جدول مرجع تگ picture، srcset، sizes و lazy loading
کد تگ picture در html با منابع avif و webp و جایگزین jpeg
ترتیب sourceها: فشرده‌ترین فرمت اول

lazy load تصاویر در HTML چطور انجام می‌شود؟

lazy load تصاویر در HTML فقط با اتریبیوت loading="lazy" روی img (یا iframe) انجام می‌شود؛ مرورگر دانلود تصویر را تا وقتی کاربر به نزدیکی آن اسکرول کند عقب می‌اندازد. برای این کار دیگر به کتابخانه جاوااسکریپتی نیاز نیست.

<!-- تصویر اصلی بالای صفحه: lazy نکنید -->
<img src="hero.webp" alt="ویترین شیرینی‌های تازه"
width="1600" height="900" fetchpriority="high">

<!-- تصویرهای پایین صفحه: lazy + sizes خودکار -->
<img
loading="lazy"
sizes="auto, (max-width: 600px) 100vw, 33vw"
srcset="item-300.webp 300w, item-600.webp 600w"
src="item-600.webp"
alt="کیک هویج با گردو"
width="600" height="600">

قانون طلایی این است: تصویری را که در نمای اول صفحه دیده می‌شود، به‌خصوص تصویری که احتمالاً LCP (بزرگ‌ترین المان قابل‌مشاهده) است، lazy نکنید. مقاله web.dev درباره lazy loading مرورگر هشدار می‌دهد که lazy کردن تصاویر بالای صفحه می‌تواند LCP را بدتر کند. web.dev مقدار خوب LCP را ۲٫۵ ثانیه یا کمتر می‌داند. همچنین طبق MDN، بارگذاری تنبل فقط وقتی جاوااسکریپت مرورگر فعال است اعمال می‌شود.

sizes=”auto” برای تصاویر lazy

یک قابلیت جدیدتر، مقدار auto در sizes است که فقط همراه loading="lazy" معتبر است؛ چون تا زمان بارگذاری تصویر lazy، مرورگر طرح‌بندی و CSS را دارد و خودش عرض واقعی را می‌داند. MDN توصیه می‌کند بعد از auto، مقدارهای جایگزین معمولی را هم بنویسید تا مرورگرهایی که auto را نمی‌شناسند از آن‌ها استفاده کنند (مثل مثال بالا).

lazy loading برای iframe

نقشه، ویدیوی آپارات یا هر محتوای iframe در پایین صفحه هم با همین اتریبیوت تنبل بارگذاری می‌شود. iframe را در قسمت ۱۹ کامل‌تر بررسی می‌کنیم:

<!-- iframe هم lazy می‌شود -->
<iframe
src="https://www.example.com/map"
title="نقشه موقعیت شعبه مرکزی"
width="600" height="400"
loading="lazy"></iframe>

srcset یا picture؛ کدام را انتخاب کنیم؟

اگر همان تصویر را فقط در اندازه‌های مختلف می‌خواهید، srcset و sizes روی img کافی و ساده‌تر است؛ اگر فرمت متفاوت یا تصویر و برش متفاوت برای صفحه‌های مختلف می‌خواهید، از picture استفاده کنید. picture انعطاف بیشتری دارد اما کد بیشتری می‌خواهد.

نیازراه‌حلمرورگر انتخاب می‌کند؟
همان عکس، عرض‌های مختلفimg + srcset (w) + sizesبله؛ بر اساس عرض، تراکم و شبکه
لوگو یا آیکون با اندازه ثابتimg + srcset (x)بله؛ بر اساس تراکم پیکسل
AVIF یا WebP با جایگزینpicture + source typeخیر؛ اولین فرمت پشتیبانی‌شده
برش متفاوت برای موبایلpicture + source mediaخیر؛ اولین شرط درست الزامی است
لوگوی حالت تاریکpicture + prefers-color-schemeخیر؛ بر اساس تنظیم کاربر
انتخاب بین srcset و تگ picture بر اساس نیاز

از تجربه تیم siloow: تصاویر ریسپانسیو در وردپرس

وردپرس به‌طور خودکار برای هر تصویر آپلودشده چند اندازه می‌سازد و برای تصاویر داخل محتوا srcset و sizes تولید می‌کند. در قالب‌های اختصاصی که تیم siloow می‌سازد، متوجه شدیم این sizes پیش‌فرض برای بسیاری از طرح‌بندی‌ها دقیق نیست؛ مثلاً در یک گرید سه‌ستونی محصولات، sizes پیش‌فرض باعث می‌شد مرورگر تصویری نزدیک به عرض کامل صفحه دانلود کند. راه‌حل ما این بود که برای هر جایگاه تصویر در قالب (کارت محصول، تصویر شاخص مقاله، بنر صفحه اصلی) اندازه تصویر اختصاصی تعریف کنیم و sizes را متناسب با همان طرح‌بندی بنویسیم. برای بنر صفحه اصلی هم از picture با نسخه جداگانه موبایل استفاده کردیم و آن را lazy نکردیم. این تغییرات باعث شد حجم تصاویر دانلودشده در موبایل به‌طور محسوسی کم شود.

مراحل ساخت تصاویر ریسپانسیو با srcset و lazy load تصاویر
چک‌لیست هر تصویر در صفحه

اشتباهات رایج در تصاویر ریسپانسیو

  • نوشتن عددی غیر از عرض واقعی فایل جلوی w در srcset.
  • ترکیب توصیف‌گر w و x در یک srcset.
  • جا انداختن img داخل picture؛ بدون img هیچ چیزی نمایش داده نمی‌شود.
  • نوشتن alt روی source به‌جای img.
  • ترتیب اشتباه sourceها؛ مثلاً JPEG قبل از AVIF.
  • lazy کردن تصویر اصلی بالای صفحه.
  • ننوشتن sizes و دانلود تصویر تمام‌عرض در ستون‌های کوچک.

محدودیت‌ها و چه زمانی ساده بمانیم؟

تصاویر ریسپانسیو به چند نسخه از هر تصویر نیاز دارند و ساختن دستی آن‌ها در پروژه‌های کوچک زمان‌بر است. اگر سایت فقط چند تصویر کوچک دارد، یک img با فرمت WebP و ابعاد مناسب کافی است. در پروژه‌های بزرگ‌تر بهتر است ساخت نسخه‌ها را به CMS، ابزار build یا سرویس تصویر بسپارید و دستی ننویسید. همچنین مرورگر در انتخاب از srcset آزاد است؛ یعنی نمی‌توانید مطمئن باشید دقیقاً کدام نسخه دانلود می‌شود و نباید روی آن حساب باز کنید.

تمرین این قسمت

  1. از یک عکس چهار نسخه با عرض‌های ۴۰۰، ۸۰۰، ۱۲۰۰ و ۱۶۰۰ پیکسل بسازید و با srcset و sizes در صفحه بگذارید.
  2. در DevTools مرورگر (تب Network) بررسی کنید در عرض‌های مختلف پنجره کدام نسخه دانلود می‌شود.
  3. همان عکس را با picture و سه فرمت AVIF، WebP و JPEG ارائه دهید.
  4. یک بنر بسازید که در موبایل نسخه عمودی و در دسکتاپ نسخه افقی نمایش دهد.
  5. یک گالری ۹ تصویری بسازید که فقط تصاویر پایین صفحه lazy باشند.

جمع‌بندی و خلاصه

  • srcset در html نسخه‌های مختلف تصویر را معرفی می‌کند و مرورگر مناسب‌ترین را انتخاب می‌کند.
  • sizes در html عرض نمایش تصویر را به مرورگر می‌گوید؛ پیش‌فرض آن 100vw است.
  • تگ picture در html برای فرمت‌های جایگزین و هدایت هنری است و همیشه یک img در انتها دارد.
  • lazy load تصاویر با loading=”lazy” انجام می‌شود، اما تصویر بالای صفحه نباید lazy باشد.
  • alt، width و height همیشه روی img نوشته می‌شوند، نه روی source.

همه قسمت‌ها در دوره کدپرس فهرست شده‌اند و اگر تازه شروع کرده‌اید، از قسمت ۱: HTML چیست؟ شروع کنید. برای دیدن جایگاه سرعت و تصاویر در یک پروژه واقعی، راهنمای کامل طراحی سایت را بخوانید. در قسمت بعد، «قسمت ۱۱ – لیست‌ها در HTML؛ ul، ol و dl»، سراغ لیست‌های مرتب و نامرتب و شماره‌گذاری فارسی می‌رویم.

منابع

سوالات متداول درباره تگ picture در html

تفاوت تگ picture و srcset چیست؟

srcset روی img نسخه‌های مختلف یک تصویر را معرفی می‌کند و انتخاب نهایی با مرورگر است. تگ picture برای وقتی است که فرمت متفاوت یا تصویر و برش متفاوت برای شرایط مختلف می‌خواهید و مرورگر باید اولین source مناسب را دقیقاً رعایت کند.

alt را در تگ picture کجا بنویسم؟

alt، width و height همیشه روی img داخل picture نوشته می‌شوند. source اتریبیوت alt ندارد و img آخرین فرزند picture و تنها المانی است که واقعاً نمایش داده می‌شود.

آیا برای lazy load تصاویر هنوز به جاوااسکریپت نیاز است؟

خیر. مرورگرهای امروزی اتریبیوت loading=”lazy” را روی img و iframe پشتیبانی می‌کنند. کتابخانه‌های جاوااسکریپتی فقط برای نیازهای خاص مثل افکت‌های نمایش تدریجی لازم هستند.

اگر sizes را ننویسم چه می‌شود؟

مرورگر مقدار پیش‌فرض 100vw را فرض می‌کند، یعنی تصور می‌کند تصویر تمام عرض صفحه را می‌گیرد. در ستون‌ها و کارت‌های کوچک، این یعنی دانلود تصویری بزرگ‌تر از نیاز و هدر رفتن حجم اینترنت کاربر.

وردپرس srcset را خودکار می‌سازد؛ باز هم باید کاری کنم؟

وردپرس برای تصاویر محتوا srcset و sizes پیش‌فرض تولید می‌کند، اما sizes پیش‌فرض همیشه با طرح‌بندی قالب شما منطبق نیست. در قالب‌های اختصاصی بهتر است sizes را برای هر جایگاه تصویر متناسب با طرح‌بندی تنظیم کنید.

اشتراک‌گذاری