בעבר, מפתחי אתרים נתקלו בקשיים במדידת המהירות שבה התוכן הראשי של דף אינטרנט נטען ומוצג למשתמשים. מדדים ישנים יותר כמו load או DOMContentLoaded לא עובדים טוב כי הם לא בהכרח תואמים למה שהמשתמש רואה במסך. בנוסף, מדדי ביצועים חדשים יותר שמתמקדים במשתמש, כמו הצגת תוכן ראשוני (FCP), מתעדים רק את תחילת חוויית הטעינה. אם בדף מוצג מסך הפתיחה או אינדיקטור טעינה, הרגע הזה לא רלוונטי במיוחד למשתמש.
בעבר המלצנו על מדדי ביצועים כמו המהירות שבה נטען רכיב חשוב ראשון (FMP) ואינדקס המהירות (SI) (שניהם זמינים ב-Lighthouse) כדי לתעד יותר את חוויית הטעינה אחרי הבדיקה הראשונית. אבל המדדים האלה מורכבים, קשים להסבר ולרוב שגויים – כלומר, עדיין אי אפשר לזהות מתי התוכן העיקרי של הדף נטען.
על סמך דיונים בקבוצת העבודה של W3C בנושא ביצועי אינטרנט ומחקרים שבוצעו ב-Google, גילינו שדרך מדויקת יותר למדוד מתי התוכן הראשי של דף נטען היא לבדוק מתי הרכיב הגדול ביותר עבר רינדור.
מהו LCP?
מדד LCP מדווח על זמן העיבוד של התמונה, הבלוק של הטקסט או הסרטון הגדול ביותר שגלוי באזור התצוגה, ביחס למועד שבו המשתמש מנווט לדף בפעם הראשונה.
מהו ציון LCP טוב?
כדי לספק חוויית משתמש טובה, צריך לשאוף שהזמן של המדד Largest Contentful Paint יהיה 2.5 שניות או פחות. כדי לוודא שאתם עומדים ביעד הזה עבור רוב המשתמשים, סף טוב למדידה הוא הפרמטר 75th percentile של טעינת הדפים, שמפולח לפי מכשירים ניידים ומחשבים.
אילו אלמנטים נחשבים?
כפי שמצוין כרגע ב-LCP LCP, סוגי הרכיבים שנלקחים בחשבון עבור Largest Contentful Paint (LCP) הם:
- רכיבי
<img>
(זמן הצגת המסגרת הראשונה משמש לתוכן אנימציה, כמו קובצי GIF או קובצי PNG עם אנימציה) - רכיבי
<image>
בתוך רכיב<svg>
- רכיבי
<video>
(משתמשים בזמן הטעינה של תמונת הפוסטרים או בזמן הצגת הפריים הראשון בסרטונים – המוקדם מביניהם) - אלמנט עם תמונת רקע שנטענת באמצעות הפונקציה
url()
(בניגוד לשיפוע CSS) - רכיבים ברמת הבלוק שמכילים צומתי טקסט או רכיבי טקסט אחרים ברמה מוטבעת.
חשוב לדעת שהחלטנו להגביל את הרכיבים לקבוצה המוגבלת הזו כדי לשמור על פשטות בהתחלה. בעתיד ייתכן שנוסיף עוד רכיבים (כמו התמיכה המלאה ב-<svg>
) ככל שייערך מחקר נוסף.
בנוסף לכך שמדד LCP מתייחס רק לחלק מהאלמנטים, הוא משתמש בהיגוריקה כדי להחריג אלמנטים מסוימים שהמשתמשים צפויים לראות כ'לא מכילים תוכן'. בדפדפנים מבוססי Chromium, אלה כוללים:
- רכיבים עם שקיפות 0, שאינם גלויים למשתמש
- רכיבים שמכסים את אזור התצוגה במלואו, וכנראה נחשבים לרקע ולא לתוכן
- תמונות placeholder או תמונות אחרות עם אנטרופיה נמוכה, שסביר להניח שלא משקפות את התוכן האמיתי של הדף
סביר להניח שהדפדפנים ימשיכו לשפר את שיטות הניתוח האלה כדי להבטיח שנוכל לעמוד בציפיות של המשתמשים לגבי הרכיב הגדול ביותר שמכיל תוכן.
ההיוריסטיקה ה"תוכןית" האלה עשויה להיות שונה מזו שמשמשות את השיטה המהירות שבה נטען רכיב התוכן הראשון (FCP), כי היא עשויה להביא בחשבון חלק מהאלמנטים האלה, כמו תמונות placeholder או תמונות של אזור התצוגה המלא, גם אם הם לא עומדים בדרישות של ה-LCP. למרות שהשם של שניהם כולל את המילה 'תוכן', המטרה של המדדים האלה שונה. שיטת FCP מודדת כשתוכן כלשהו צבוע למסך ו-LCP כשהתוכן הראשי צבוע, ולכן מדד ה-LCP אמור להיות סלקטיבי יותר.
איך נקבע הגודל של רכיב?
בדרך כלל, הגודל של הרכיב שמדווח עליו במדד LCP הוא הגודל שגלוי למשתמש באזור התצוגה. אם האלמנט חורג מאזור התצוגה, או אם חלק מהאלמנט חתוך או שיש לו חרגה לא נראית, החלקים האלה לא נספרים בגודל האלמנט.
לגבי רכיבי תמונה ששינו את הגודל מהגודל המובנה שלהם, הגודל שמדווח הוא הגודל הגלוי או הגודל המובנה, לפי הגודל הקטן מביניהם.
ברכיבי טקסט, המדד LCP מתייחס רק למלבן הקטן ביותר שיכול להכיל את כל צמתי הטקסט.
בכל הרכיבים, מדד LCP לא מתייחס לשוליים, למרווחים או לשוליים שהוחלו באמצעות CSS.
מתי מדווח LCP?
דפי אינטרנט נטענים לעיתים קרובות בשלבים, וכתוצאה מכך יכול להיות שהרכיב הגדול ביותר בדף ישתנה.
כדי לטפל באפשרות לשינוי כזה, הדפדפן שולח אירוע PerformanceEntry
מסוג largest-contentful-paint
שמזהה את רכיב התוכן הגדול ביותר ברגע שהדפדפן מצייר את המסגרת הראשונה. אבל לאחר מכן, אחרי שרינדור של המסגרות הבאות, הוא ישלח PerformanceEntry
נוסף בכל פעם שהרכיב עם התוכן הגדול ביותר ישתנה.
לדוגמה, בדף עם טקסט ותמונה ראשית, הדפדפן עשוי להציג בהתחלה רק את הטקסט. בשלב הזה, הדפדפן ישלח רשומה largest-contentful-paint
שבה סביר להניח שהנכס element
יפנה ל-<p>
או ל-<h1>
. מאוחר יותר, ברגע שהטעינה של התמונה הראשית (Hero) תסתיים, תישלח רשומה שנייה של largest-contentful-paint
, והמאפיין element
שלה יפנה אל <img>
.
רכיב יכול להיחשב כרכיב התוכן הגדול ביותר רק אחרי שהוא עבר רינדור וגלוי למשתמש. תמונות שעדיין לא נטענו לא נחשבות כ'עברו רינדור'. גם לא צמתי טקסט שמשתמשים בגופני אינטרנט במהלך התקופה של חסימת הגופנים. במקרים כאלה, יכול להיות שידווח על רכיב קטן יותר כרכיב התוכן הגדול ביותר, אבל ברגע שהעיבוד של הרכיב הגדול יותר יסתיים, ייווצר PerformanceEntry
נוסף.
בנוסף לתמונות ולגופנים שנטענים מאוחר, יכול להיות שדף יוסיף רכיבים חדשים ל-DOM כשתוכן חדש יהיה זמין. אם אחד מהרכיבים החדשים האלה גדול מהרכיב הקודם עם התוכן הגדול ביותר, PerformanceEntry
חדש יירשם גם כן.
אם הרכיב הגדול ביותר שמכיל תוכן יוסר מאזור התצוגה או אפילו מה-DOM, הוא יישאר הרכיב הגדול ביותר שמכיל תוכן, אלא אם רכיב גדול יותר יעובד.
הדפדפן יפסיק לדווח על רשומות חדשות ברגע שהמשתמש ייצור אינטראקציה עם הדף (באמצעות הקשה, גלילה או הקשה על מקש), כי אינטראקציה של המשתמש משנה לעיתים קרובות את מה שגלוי למשתמש (הדבר נכון במיוחד לגבי גלילה).
למטרות ניתוח, יש לדווח רק על PerformanceEntry
שנשלח לאחרונה לשירות ניתוח הנתונים שלך.
זמן הטעינה לעומת זמן הרינדור
מטעמי אבטחה, חותמת הזמן של עיבוד התמונות לא נחשפת בתמונות ממקורות שונים שחסרה בהן הכותרת Timing-Allow-Origin
. במקום זאת, רק זמן הטעינה שלהם נחשף (כי הוא כבר נחשף דרך ממשקי API רבים אחרים של אינטרנט).
מצב כזה עלול להוביל למצב שנראה בלתי אפשרי, שבו זמן הטעינה של התוכן הוויזואלי המשמעותי (LCP) מדווח על ידי ממשקי API לאינטרנט מוקדם יותר מזמן הטעינה הראשונית של דף הנחיתה (FCP). זה לא המצב, אלא נראה כך רק בגלל הגבלת האבטחה הזו.
כשהדבר אפשרי, מומלץ תמיד להגדיר את הכותרת Timing-Allow-Origin
כדי שהמדדים יהיו מדויקים יותר.
איך מטפלים בשינויים מבחינת הפריסה והגודל של רכיבים?
כדי לצמצם את זמן הטיפול בביצועים שנדרש לחישוב ולשליחה של רשומות ביצועים חדשות, שינויים בגודל או במיקום של רכיב לא יוצרים מועמדים חדשים ל-LCP. רק הגודל והמיקום הראשוניים של האובייקט באזור התצוגה נלקחים בחשבון.
כלומר, יכול להיות שלא יתבצע דיווח על תמונות שתחילה הן מוצגות מחוץ למסך ולאחר מכן הן עוברות למסך. המשמעות היא גם שרכיבים שעבר להם עיבוד ראשוני באזור התצוגה ואז נדחפו למטה, מחוץ לתצוגה, עדיין ידווחו על הגודל הראשוני שלהם באזור התצוגה.
דוגמאות
ריכזנו כאן כמה דוגמאות למקרים שבהם אירוע ה-Largest Contentful Paint מתרחש בכמה אתרים פופולריים:
בשני צירי הזמן שלמעלה, הרכיב הגדול ביותר משתנה ככל שהתוכן נטען. בדוגמה הראשונה, תוכן חדש נוסף ל-DOM, וכתוצאה מכך הרכיב הגדול ביותר משתנה. בדוגמה השנייה, הפריסה משתנה והתוכן שהיה הגדול ביותר בעבר מוסר מאזור התצוגה.
במקרים רבים תוכן שנטען מאוחר הוא גדול יותר מתוכן שכבר נמצא בדף, אך אין זה בהכרח נכון. בשתי הדוגמאות הבאות, אירוע ה-LCP מתרחש לפני שהדף נטען במלואו.
בדוגמה הראשונה, הלוגו של Instagram נטען מוקדם יחסית, והוא נשאר המרכיב הגדול ביותר גם כאשר תוכן אחר מוצג בהדרגה. בדוגמה של דף תוצאות החיפוש ב-Google, האלמנט הגדול ביותר הוא פסקת טקסט שמוצגת לפני שטוענים את התמונה או הלוגו. מכיוון שכל התמונות הנפרדות קטנות מהפסקה הזו, היא נשארת הרכיב הגדול ביותר לאורך כל תהליך הטעינה.
איך מודדים את מדד LCP
אפשר למדוד LCP בשיעור ה-Lab או בשדה, והוא זמין בכלים הבאים:
כלים לשטח
- הדוח לגבי חוויית המשתמש ב-Chrome
- PageSpeed Insights
- Search Console (דוח מדדי הליבה לבדיקת חוויית המשתמש באתר)
- ספריית JavaScript של
web-vitals
כלי Labs
מדידת LCP ב-JavaScript
כדי למדוד את LCP ב-JavaScript, אפשר להשתמש ב-Largest Contentful Paint API. בדוגמה הבאה מוסבר איך ליצור PerformanceObserver
שמקשיב לרשאות largest-contentful-paint
ומתעדים אותן ביומן במסוף.
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('LCP candidate:', entry.startTime, entry);
}
}).observe({type: 'largest-contentful-paint', buffered: true});
בדוגמה שלמעלה, כל רשומה ב-largest-contentful-paint
ביומן מייצגת את המועמד הנוכחי ל-LCP. באופן כללי, הערך של startTime
ברשומה האחרונה שמונפקת הוא הערך של LCP – אבל זה לא תמיד המצב. לא כל הרשומות של largest-contentful-paint
תקינות למדידת LCP.
בקטע הבא מפורטים ההבדלים בין מה שמדווח ב-API לבין אופן החישוב של המדד.
ההבדלים בין המדד לבין ה-API
- ה-API ישלח
largest-contentful-paint
רשומות של דפים שנטענים בכרטיסיית רקע, אבל צריך להתעלם מהדפים האלה בחישוב LCP. - ה-API ימשיך לשלוח
largest-contentful-paint
רשומות אחרי שדף הועבר לרקע, אבל צריך להתעלם מרשומות אלה בעת חישוב LCP (ניתן להתייחס לרכיבים רק אם הדף היה בחזית במשך כל הזמן). - ה-API לא מדווח על רשומות
largest-contentful-paint
כשהדף משוחזר מהמטמון של 'הקודם'/'הבא', אבל צריך למדוד את LCP במקרים האלה כי המשתמשים חווים אותם כביקור נפרד בדף. - ה-API לא מתייחס לרכיבים בתוך iframe, אבל המדד כן מתייחס אליהם כי הם חלק מחוויית המשתמש בדף. בדפים עם LCP בתוך iframe – לדוגמה, תמונת פוסטרים בסרטון מוטמע – ההבדל יופיע בין CrUX לבין RUM. כדי למדוד את LCP בצורה נכונה, כדאי להביא בחשבון את הגורמים האלה. תמונות משנה יכולות להשתמש ב-API כדי לדווח על רשומות
largest-contentful-paint
שלהן למסגרת ההורה לצורך צבירה. - ה-API מודד את LCP מתחילת הניווט, אבל בדפים שעברו רינדור מראש צריך למדוד את LCP מ-
activationStart
כי זהו הזמן של LCP כפי שהמשתמש חווה אותו.
במקום לזכור את כל ההבדלים העדינים האלה, מפתחים יכולים להשתמש בספריית JavaScript של web-vitals
כדי למדוד את LCP, והיא מטפלת בהבדלים האלה בשבילכם (במקרים שבהם זה אפשרי – שימו לב שהבעיה של iframe לא מכוסה):
import {onLCP} from 'web-vitals';
// Measure and log LCP as soon as it's available.
onLCP(console.log);
בקוד המקור של onLCP()
תמצאו דוגמה מלאה למדידת LCP ב-JavaScript.
מה קורה אם הרכיב הגדול ביותר הוא לא החשוב ביותר?
במקרים מסוימים, הרכיב (או הרכיבים) החשובים ביותר בדף אינו זהה לרכיב הגדול ביותר, ובמקום זאת ייתכן שמפתחים ירצו למדוד את זמני העיבוד של רכיבים אחרים אלה. הדבר אפשרי באמצעות Element Timing API, כפי שמתואר במאמר בנושא מדדים מותאמים אישית.
איך משפרים את LCP
יש מדריך מלא בנושא אופטימיזציה של LCP שיעזור לכם לזהות את זמני ה-LCP בשטח ולהשתמש בנתוני המעבדה כדי להציג פירוט שלהם ולבצע אופטימיזציה.
מקורות מידע נוספים
- לקחים ממעקב הביצועים ב-Chrome מאת Annie Sullivan ב-performance.now() (2019)
יומן שינויים
מדי פעם מתגלים באגים בממשקי ה-API המשמשים למדידת המדדים, ולפעמים בהגדרות של המדדים עצמם. לכן, לפעמים צריך לבצע שינויים, והשינויים האלה יכולים להופיע בדוחות הפנימיים ובלוחות הבקרה שלכם כשיפורים או נסיגות.
כדי לעזור לכם לנהל את הנושא, כל השינויים בהטמעה או בהגדרה של המדדים האלה יופיעו ביומן השינויים הזה.
אם יש לכם משוב לגבי המדדים האלה, אתם יכולים לשלוח אותו לקבוצת Google web-vitals-feedback.