תחביר תיאורי

האלמנט <picture> לא מעבד שום דבר בפני עצמו, אלא פועל כמנוע החלטות של רכיב <img> פנימי, ואומר לו מה לעבד. <picture> פועל לפי תקדים שכבר הוגדר על ידי הרכיבים <audio> ו-<video>: רכיב wrapper שמכיל רכיבי <source> נפרדים.

<picture>
   <source …>
   <source …>
    <img …>
</picture …>

ב-<img> הפנימי הזה יש גם תבנית חזרה מהימנה לדפדפנים ישנים יותר, ללא תמיכה בתמונות רספונסיביות: אם הרכיב <picture> לא מזוהה על ידי הדפדפן של המשתמש, המערכת מתעלמת ממנו. גם רכיבי <source> נמחקים, כי הדפדפן לא יזהה אותם בכלל, או שלא יהיה להם הקשר משמעותי ללא הורה <video> או <audio>. עם זאת, כל דפדפן יזוהה את רכיב ה-<img> הפנימי, והמקור שצוין ב-src שלו יעובד כמצופה.

תמונות "בימוי אומנותי" עם <picture>

בדרך כלל, ביצוע שינויים בתוכן או ביחס גובה-רוחב של תמונה על סמך גודל התמונה בדף נחשב כ'תמונות רספונסיביות עם אומנות'. srcset ו-sizes מתוכננים לפעול בצורה בלתי נראית, ולהחליף באופן חלק בין המקורות לפי הכתבה של הדפדפן של המשתמש. עם זאת, לפעמים רוצים לשנות מקורות בנקודות עצירה כדי להדגיש בצורה טובה יותר את התוכן, באותו אופן שבו מתאימים את פריסות הדף. לדוגמה: תמונת כותרת ברוחב מלא עם מיקוד מרכזי קטן עשויה להתאים לאזור תצוגה גדול:

תמונת כותרת ברוחב כותרת של פרח סגלגל מוקף עלים וגבעות, ודבורת דבש מביקרת אותה.

אבל אם תקטין את התמונה כך שתתאים לאזורי תצוגה קטנים, אתה עלול לאבד את המיקוד המרכזי של התמונה:

תמונת כותרת ברוחב כותרת של פרח סגלגל, מוקטנת. דבורה כמעט שלא גלויה.

הנושא של מקורות התמונות האלה זהה, אבל כדי להתמקד טוב יותר בנושא הזה מבחינה חזותית, כדאי שהפרופורציות של מקור התמונה ישתנו בין נקודות עצירה (breakpoint). לדוגמה, זום קטן יותר במרכז התמונה וחלק מהפרטים בקצוות נחתכים:

חיתוך מוגדל של פרח סגלגל.

אפשר להשיג סוג כזה של 'חיתוך' באמצעות CSS, אבל משתמש עלול לבקש את כל הנתונים שמהם מורכבת התמונה, למרות שייתכן שלעולם לא יראה אותה.

לכל רכיב source יש מאפיינים שמגדירים את התנאים לבחירה ב-source: media, שמקבל שאילתת מדיה, ו-type שמקבל סוג מדיה (נקרא בעבר "סוג MIME"). נבחר הערך <source> הראשון בסדר המקור שתואם להקשר הגלישה הנוכחי של המשתמש, והתוכן של המאפיין srcset באותו source ישמש כדי לקבוע את המועמדים המתאימים להקשר הזה. בדוגמה הזו, השדה source הראשון עם מאפיין media שתואם לגודל אזור התצוגה של המשתמש יהיה הערך שנבחר:

<picture>
  <source media="(min-width: 1200px)" srcset="wide-crop.jpg">
  <img src="close-crop.jpg" alt="…">
</picture>

יש לציין תמיד את השדה img הפנימי בסוף הסדר – אם אף אחד מהאלמנטים של source לא תואם לקריטריונים media או type, התמונה תפעל כמקור 'ברירת מחדל'. אם אתם משתמשים ב-min-width שאילתות מדיה, מומלץ שקודם יהיו המקורות הגדולים ביותר, כפי שמתואר בקוד הקודם. כשמשתמשים ב-max-width שאילתות מדיה, מומלץ לציין קודם את המקור הקטן ביותר.

<picture>
   <source media="(max-width: 400px)" srcset="mid-bp.jpg">
   <source media="(max-width: 800px)" srcset="high-bp.jpg">
   <img src="highest-bp.jpg" alt="…">
</picture>

כשבוחרים מקור על סמך הקריטריונים שציינתם, המאפיין srcset ב-source מועבר ל-<img> כאילו הוא הוגדר ב-<img> עצמו. כלומר, אתם יכולים להשתמש ב-sizes גם כדי לבצע אופטימיזציה של מקורות תמונות שמוצגים בגרפיקה.

<picture>
   <source media="(min-width: 800px)" srcset="high-bp-1600.jpg 1600w, high-bp-1000.jpg 1000w">
   <source srcset="lower-bp-1200.jpg 1200w, lower-bp-800.jpg 800w">
   <img src="fallback.jpg" alt="…" sizes="calc(100vw - 2em)">
</picture>

כמובן שתמונה עם פרופורציות שיכולות להשתנות בהתאם לרכיב <source> שנבחר גורמת לבעיית ביצועים: <img> תומך רק במאפיין width ובמאפיין height אחד, אבל השמטת המאפיינים האלה עלולה להוביל לחוויית משתמש נמוכה יותר באופן למדידה. כדי להביא בחשבון זאת, תוספת חדשה יחסית - אך נתמכת היטב - למפרט ה-HTML, שמאפשרת להשתמש במאפיינים height ו-width ברכיבי <source>. הן נועדו לצמצם את התנודות בפריסה בדיוק כמו שצריך לעשות זאת ב-<img>, תוך שמירה על השטח המתאים בפריסה לכל רכיב <source> שנבחר.

<picture>
   <source
      media="(min-width: 800px)"
      srcset="high-bp-1600.jpg 1600w, high-bp-1000.jpg 1000w"
      width="1600"
      height="800">
   <img src="fallback.jpg"
      srcset="lower-bp-1200.jpg 1200w, lower-bp-800.jpg 800w"
      sizes="calc(100vw - 2em)"
      width="1200"
      height="750"
      alt="…">
</picture>

חשוב לציין שכיוון התמונה יכול לשמש יותר מהחלטות על סמך גודל אזור התצוגה, וצריך להשתמש בו, כי ברוב המקרים אפשר לטפל ביעילות רבה יותר באמצעות srcset/sizes. לדוגמה, בחירת מקור תמונה שמתאים יותר לערכת הצבעים לפי ההעדפות של המשתמש:

<picture>
   <source media="(prefers-color-scheme: dark)" srcset="hero-dark.jpg">
   <img srcset="hero-light.jpg">
</picture>

המאפיין type

המאפיין type מאפשר להשתמש במנוע ההחלטה עם בקשה יחידה של האלמנט <picture>, כדי להציג פורמטים של תמונות רק לדפדפנים שתומכים בהם.

כפי שלמדתם בקטע Image Formats and Compression, אי אפשר לזהות קידוד שהדפדפן לא יכול לנתח אפילו כנתוני תמונה.

לפני השקת האלמנט <picture>, כדי להשתמש בפתרונות הקצה המעשיים ביותר להצגת פורמטים חדשים של תמונות, הדפדפן היה צריך לבקש ולנתח קובץ תמונה לפני שניתן היה לקבוע אם למחוק אותו ולטעון קובץ חלופי. דוגמה נפוצה הייתה סקריפט בקווים הבאים:

   <img src="image.webp"
    data-fallback="image.jpg"
    onerror="this.src=this.getAttribute('data-fallback'); this.onerror=null;"
    alt="...">

עם הדפוס הזה, עדיין תתבצע בקשה ל-image.webp בכל דפדפן, כלומר העברה מבוזבזת לדפדפנים ללא תמיכה ב-WebP. דפדפנים שלא יוכלו לנתח את הקידוד של WebP ייצרו אירוע onerror, ויחליפו את הערך data-fallback ב-src. זה היה פתרון בזבוז, אבל שוב, גישות כאלה היו האפשרות היחידה שהייתה זמינה בממשק הקצה. חשוב לזכור שהדפדפן מתחיל לשלוח בקשות לתמונות לפני שיש סקריפטים מותאמים אישית שיש להם הזדמנות להפעיל, או אפילו לנתח, כך שלא יכולנו למנוע את התהליך הזה.

הרכיב <picture> תוכנן באופן מפורש למנוע את הבקשות המיותרות האלה. לדפדפן אין עדיין דרך לזהות פורמט שלא נתמך בלי לבקש אותו, אבל באמצעות המאפיין type הדפדפן מזהיר מראש את קידוד המקור כדי לקבוע אם להגיש בקשה או לא.

במאפיין type מספקים את סוג המדיה (לשעבר MIME) של מקור התמונה שצוין במאפיין srcset של כל <source>. כך הדפדפן מספק לדפדפן את כל המידע שצריך כדי לקבוע מיד אם אפשר לפענח את מועמד התמונה שסופק על ידי source בלי לשלוח בקשות חיצוניות – אם סוג המדיה לא מזוהה, המערכת מתעלמת מה-<source> ומכל המועמדים שלו, והדפדפן ממשיך.

<picture>
 <source type="image/webp" srcset="pic.webp">
 <img src="pic.jpg" alt="...">
</picture>

כאן, כל דפדפן שתומך בקידוד WebP יזהה את סוג המדיה image/webp שצוין במאפיין type של האלמנט <source>, ויבחר את <source>, ומאחר שסיפקנו רק מועמד אחד ב-srcset - מורה ל-<img> הפנימי לבקש, להעביר ולעבד pic.webp. כל דפדפן ללא תמיכה ב-WebP יתעלם מ-source, ובהיעדר הוראות הפוכה, <img> יציג את התוכן של src כפי שנעשה מאז 1992. כמובן שאין צורך לציין כאן רכיב <source> שני עם type="image/jpeg", כמובן שאפשר להניח תמיכה אוניברסלית ב-JPEG.

בלי קשר להקשר של הגלישה של המשתמש, הכול מתבצע באמצעות העברת קובץ אחת, ורוחב פס שלא מבזבז על מקורות תמונה שאי אפשר לעבד. זוהי גם חשיבה קדימה: פורמטים חדשים ויעילים יותר של קבצים יתווספו לסוגי מדיה משל עצמם, ונוכל להשתמש בהם הודות ל-picture – ללא JavaScript, ללא תלות בצד השרת והמהירות של <img>.

העתיד של תמונות רספונסיביות

כל דפוסי הסימון שנדונו כאן היו עלייה משמעותית מבחינת תקינה: שינוי הפונקציונליות של משהו קיים ומרכזי באינטרנט, כמו <img>, לא היה צעד קטן, וחבילת הבעיות שאותן היו מנסים לפתור היו נרחבות, בפחות או יותר. אם חשבתם שיש הרבה מקום לשיפור בדפוסי הסימון האלה, אתם צודקים לגמרי. מלכתחילה, הסטנדרטים האלה נועדו לספק בסיס לטכנולוגיות עתידיות.

כל הפתרונות האלה התבססו בהכרח על תגי עיצוב, כך שהם ייכללו במטען הייעודי (payload) הראשוני של השרת ויגיעו בזמן לדפדפן כדי לבקש מקורות של תמונות – מגבלה שהובילה למאפיין sizes לא כללי.

עם זאת, מאז שהתכונות האלה הושקו בפלטפורמת האינטרנט, הושקה שיטה מותאמת לדחיית בקשות לתמונות. כדי לדחות בקשות לתמונות מחוץ לאזור התצוגה הראשוני של המשתמש, צריך לשלוח בקשות לרכיבי <img> עם המאפיין loading="lazy" רק אחרי שפריסת הדף ידועה, וכך להימנע מבקשות מיותרות. מכיוון שהדפדפן מבין לגמרי את פריסת הדף בזמן שליחת הבקשות האלה, הוצע מאפיין sizes="auto" כתוספת למפרט ה-HTML כדי למנוע עבודה של מאפייני sizes שנכתבו באופן ידני במקרים כאלה.

יש גם תוספות לרכיב <picture> באופק, כדי להתאים לשינויים מרגשים במיוחד באופן שבו אנחנו מעצבים פריסות דפים. מידע על אזור התצוגה הוא בסיס מושכל לקבלת החלטות לגבי פריסה ברמה גבוהה, אבל הוא מונע מאיתנו לגשת לפיתוח ברמת הרכיב במלואו – כלומר רכיב שניתן להשמיט לכל חלק בפריסת הדף, עם סגנונות שמתאימים לשטח שהרכיב עצמו תופס בו. הבעיה הזו הובילה ליצירת שאילתות של קונטיינר: שיטה לעיצוב רכיבי עיצוב שמבוססת על גודל הקונטיינר ההורה שלהם, במקום על אזור התצוגה בלבד.

התחביר של שאילתת הקונטיינר רק התייצב, והתמיכה בדפדפן מוגבלת מאוד, אבל בזמן הכתיבה - התוספת של טכנולוגיות הדפדפן שמאפשרות זאת תספק לאלמנט <picture> את אותה פעולה: מאפיין container פוטנציאלי שמאפשר קריטריוני בחירה של <source> על סמך השטח שנכלל ב-<img> של האלמנט <picture>, במקום על סמך גודל אזור התצוגה.

אם זה נשמע קצת מעורפל, אז יש סיבה טובה לכך: הדיונים האלה על סטנדרטים באינטרנט נמשכים, אבל רחוקים מלהיקבע - אי אפשר להשתמש בהם עדיין.

תגי עיצוב של תמונות רספונסיביים מבטיחים שרק עם הזמן יהיה קל יותר לעבוד איתם, כמו כל טכנולוגיית אינטרנט, אבל יש מספר שירותים, טכנולוגיות ומסגרות שיכולים לעזור להקל על העבודה הידנית של תגי עיצוב אלה. במודול הבא נסביר איך לשלב את כל מה שלמדנו על פורמטים של תמונות, דחיסה ותמונות רספונסיביות בתהליך הפיתוח המודרני.