בעיות עיקריות בביצועים

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

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

דחיית בקשות תמונה

אתם עומדים ללמוד מספר דרכים לוודא שבקשות התמונה שלכם יהיו קטנות ויעילות ככל האפשר, אבל הבקשה המהירה ביותר לתמונה תהיה תמיד זו שלא מתבצעת אף פעם. קודם כול, אני רוצה להסביר מהו השינוי הכי משמעותי שאתם יכולים לבצע באופן שהצגת נכסי התמונות למשתמשים שלכם: המאפיין loading="lazy".

<img src="image.jpg" loading="lazy" alt="…">

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

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

אבל יש מלכוד: דחיית הבקשות האלה פירושה לא לנצל את התהליכים שעברו אופטימיזציה במיוחד לדפדפנים כדי לבקש תמונות מוקדם ככל האפשר. אם נעשה שימוש ב-loading="lazy" באלמנטים של img לכיוון החלק העליון של הפריסה — ולכן יש סיכוי גבוה יותר שהתצוגה תהיה באזור התצוגה של המשתמש כשהדף נטען לראשונה — התמונות האלה עלולות להיראות איטיות יותר באופן משמעותי למשתמש הקצה.

קדימות האחזור

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

סביר להניח שכבר ידוע לך מהן הגישות הבסיסיות של דפדפנים לאחזור: לדוגמה, בקשה לקובץ CSS חיצוני ב<head> של מסמך נחשבת חיונית מספיק כדי לחסום את העיבוד, ובקשה לקובץ JavaScript חיצוני מעל </body> תידחה עד להשלמת העיבוד. אם הערך של מאפיין loading במאפיין <img> הוא 'עצלני', בקשת התמונה המשויכת תידחה עד שהדפדפן יקבע שהיא תוצג למשתמש. אחרת, לתמונה הזו תהיה אותה עדיפות כמו לכל תמונה אחרת בדף.

המאפיין fetchpriority מיועד להעניק למפתחים שליטה מפורטת יותר על עדיפות הנכסים, וכך לסמן משאבים בעדיפות 'גבוהה' ו 'נמוכה' ביחס למשאבים מאותו סוג. התרחישים לדוגמה של fetchpriority דומים למאפיין loading אבל רחב יותר. לדוגמה, אפשר להשתמש ב-fetchpriority="low" בתמונה שנחשפה רק בעקבות אינטראקציה של המשתמש (בין אם התמונה נמצאת באזור התצוגה של המשתמש ובין אם לא) כדי לתת עדיפות לתמונות גלויות במקום אחר בדף, או fetchpriority="high" כדי לתעדף תמונה שתהיה גלויה באופן מיידי באזור התצוגה מיד אחרי עיבוד הדף.

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

מדידת ההשפעה של תמונות

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

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

Cumulative Layout Shift ‏(CLS)

Cumulative Layout Shift (CLS) היא מדד של היציבות החזותית. זהו מדד לתיעוד יכולת השינוי בפריסה של התוכן בדף בזמן שהנכסים נטענים והדף עובר עיבוד. כל מי שהשתמש באינטרנט במשך זמן רב איבד את מקומו ברצף ארוך של טקסט, בגלל שהדף "קופץ" עקב עיבוד פתאומי של גופן Webfont או של מקור תמונה, או שרכיב אינטראקטיבי זז פתאום מהסמן. CLS גבוה הוא מטרד במקרה הטוב, וגורם לשגיאת משתמש במקרה הגרוע ביותר – למשל, לחצן 'ביטול' שמעביר את המשתמש למרחבים משותפים שבהם נמצא לחצן 'אישור', בדיוק בזמן שהמשתמש לוחץ.

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

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

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

<img src="image.jpg" height="200" width="400" alt="…">

המאפיינים האלה הפסיקו להשתמש כדי להפריד בין בעיות הסגנון שלנו בנוגע לתגי העיצוב שלנו, במיוחד מכיוון שעיצוב אתרים עם יכולת תגובה חייב לציין מידה מבוססת-אחוזים באמצעות CSS. בימים הראשונים של עיצוב אתרים רספונסיביים, האפשרות "להסיר את מאפייני width ו-height שאינם בשימוש" הייתה עצה נפוצה, כי הערכים שציינו ב-CSS שלנו — max-width: 100% ו-height: auto — היו מחליפים אותם.

<img src="image.jpg" alt="…">
img {
  max-width: 100%;
  height: auto;
}

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

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

ככלל, צריך תמיד להשתמש במאפיינים height ו-width ב-<img>, עם ערכים שתואמים לגודל הפנימי של מקור התמונה, כל עוד מקפידים לציין את height: auto לצד max-width: 100% כדי לשנות את הגובה ממאפיין ה-HTML.

<img src="image.jpg" height="200" width="400" alt="…">
img {
  max-width: 100%;
  height: auto;
}

השימוש במאפיינים width ו-height ברכיבי <img> ימנע ציון גבוה ב-CLS בגלל תמונות.

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

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

Largest Contentful Paint ‏(LCP)

המדד Largest Contentful Paint (LCP) מודד את הזמן שנדרש עד לרינדור הרכיב ה"תוכן" (תוכן) הגדול ביותר, שנראה באזור התצוגה של המשתמש – רכיב התוכן שתופס את האחוז הגדול ביותר של הדף הגלוי. על פני השטח זה נראה כאילו מדד ספציפי מדי, אבל הרכיב הזה משמש כביטוי מעשי לנקודה שבה רוב הדף עבר עיבוד, מבחינת המשתמש. LCP הוא מדד חיוני של ביצועים (מוחשיים).

מדדים כמו DOMContentLoaded או האירוע window.onload יכולים לעזור לקבוע מתי התהליך של טעינת הדף הנוכחי הושלם מבחינה טכנית, אבל הם לא בהכרח תואמים לחוויית המשתמש בדף. עיכוב קל בעיבוד רכיב מחוץ לאזור התצוגה של המשתמש יילקח בחשבון בכל אחד מהמדדים האלה, אבל סביר להניח שמשתמש בעולם האמיתי לא יבחין כלל. המשמעות של LCP ארוך היא שהחשיפה הראשונה של המשתמש בדף – התוכן החשוב ביותר באזור התצוגה הנוכחי – היא שהדף איטי או קטוע.

תפיסת המשתמשים שמתועדים על ידי LCP משפיעה ישירות על חוויית המשתמש. ניסוי שבוצע על ידי Vodafone בשנה שעברה בלבד מצא ששיפור של 31% ב-LCP לא רק הוביל לעלייה של 8% במכירות – תוצאה משמעותית כשלעצמה. הוא גם הוביל לשיפור של 15% במספר המבקרים שהפכו ללקוחות פוטנציאליים ("שיעור ביקורים בעזרת לידים") ושיפור של 11% במספר המשתמשים שנכנסו לעגלת הקניות ("שיעור המשתמשים שנכנסו לעגלת הקניות").

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

LCP מודגש במסוף של דף web.dev

יש כמה פעולות שאפשר לבצע כדי למנוע עיכובים ב-LCP: ראשית, אף פעם אין לציין loading="lazy" בתמונה בחלק העליון והקבוע, מכיוון שדחיית הבקשה עד לאחר עיבוד הדף ככל הנראה תשפיע לרעה באופן משמעותי על ציון ה-LCP. שנית, שימוש ב-fetchpriority="high" יכול ליידע את הדפדפן שיש לתעדף את ההעברה של התמונה הזו מעל תמונות אחרות בדף.

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

סיכום

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

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

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