Largest Contentful Paint (LCP) הוא מדד יציב של מדד ליבה לבדיקת חוויית המשתמש באתר, שמשמש למדידת מהירות הטעינה הנתפסת. הסמל מסמן את הנקודה בציר הזמן של טעינת הדף שבה כנראה נטען התוכן הראשי של הדף. LCP מהיר עוזר להבטיח למשתמש שהדף שימושי.
בעבר, מפתחי אתרים היו אתגר לבדוק באיזו מהירות התוכן העיקרי של דף אינטרנט נטען וגלוי למשתמשים. מדדים ישנים יותר, כמו load או DOMContentLoaded, לא פועלים היטב כי הם לא בהכרח תואמים למה שהמשתמש רואה על המסך. מדדי ביצועים חדשים יותר שמתמקדים במשתמש, כמו הצגת תוכן ראשוני (FCP) רק ההתחלה של תהליך הטעינה. אם בדף מופיע מסך פתיחה או אינדיקטור של טעינה, הרגע הזה לא רלוונטי במיוחד למשתמש.
בעבר המלצנו על מדדי ביצועים כמו First Meaningful Paint (FMP) ו-Speed Index (SI) (שניהם זמינים ב-Lighthouse) כדי לתעד יותר את חוויית הטעינה לאחר העיבוד הראשוני, אבל המדדים האלה מורכבים, קשה להסביר אותם ולרוב שגויים, כלומר הם עדיין לא מזהים מתי התוכן העיקרי של הדף נטען.
בעקבות דיונים עם W3C Web Performance Group ומחקרים שבוצעו ב-Google, גילינו שדרך מדויקת יותר למדוד מתי התוכן העיקרי בדף נטען היא לבחון מתי מתבצע עיבוד של הרכיב הגדול ביותר.
מה זה LCP?
מדד LCP מדווח על זמן הרינדור של התמונה או בלוק הטקסט הגדול ביותר שמופיע באזור התצוגה, ביחס למועד שבו המשתמש ניווט לראשונה לדף.
מהו ציון LCP טוב?
כדי לספק חוויית משתמש טובה, אתרים צריכים לשאוף ל-LCP באורך 2.5 שניות לכל היותר. כדי להבטיח שאתם עומדים ביעד הזה עבור רוב המשתמשים, סף טוב למדידה הוא האחוזון ה-75 של טעינות דפים, בפילוח בין מכשירים ניידים ומחשבים.
אילו אלמנטים נלקחים בחשבון?
כפי שצוין ב-Largest Contentful Paint API, סוגי האלמנטים שנחשבים ל'המהירות שבה נטען רכיב התוכן הכי גדול' הם:
- רכיבי
<img>
(זמן ההצגה של הפריים הראשון משמש לתוכן אנימציה, כמו קובצי GIF או קובצי PNG עם אנימציה) - רכיבי
<image>
בתוך רכיב<svg>
- רכיבי
<video>
(נעשה שימוש בזמן הטעינה של תמונת הפוסטר או בזמן ההצגה של הפריים הראשון של הסרטונים – המוקדם מביניהם) - רכיב עם תמונת רקע שנטען באמצעות הפונקציה
url()
, (בניגוד להדרגתיות של CSS) - רכיבים ברמת הבלוק שמכילים צומתי טקסט או רכיבי צאצא אחרים של רכיב טקסט ברמה הזאת.
הגבלת הרכיבים לקבוצה המוגבלת הזו הייתה מכוונת כדי להפחית את המורכבות.
יכול להיות שנוסיף בעתיד עוד אלמנטים (כמו התמיכה המלאה ב-<svg>
) ככל שיתנהלו מחקר נוסף.
בנוסף לשיקולים מסוימים בלבד, מדידות LCP משתמשות בהיוריסטיקה כדי להחריג רכיבים מסוימים שהמשתמשים עשויים לראות כ "לא שמכילים תוכן". לדפדפנים מבוססי Chromium, אלה כוללים:
- רכיבים בשקיפות של 0 שהופכים אותם לבלתי נראים למשתמש.
- רכיבים שמכסים את אזור התצוגה המלא, שצפויים להיות רכיבי רקע.
- תמונות placeholder או תמונות אחרות עם אנטרופיה נמוכה, שכנראה לא משקפות את התוכן האמיתי של הדף.
סביר להניח שדפדפנים ימשיכו לשפר את ההיוריסטיקה האלה כדי להבטיח שאנחנו תואמים לציפיות המשתמשים לגבי הרכיב התוכן הגדול ביותר.
היוריסטיקה "תוכןית" זו שונה מזו שמשמשת את FCP, שעשויה לקחת בחשבון חלק מהרכיבים האלה, כמו תמונות placeholder או תמונות של נקודת מבט מלאה, גם אם הן לא כשירות להיות מועמדים ל-LCP. למרות ששניהם משתמשים במילה "תוכן" בשמם, המטרה של המדדים האלה היא שונה. מדד ה-FCP מודד מתי כל תוכן צבוע למסך, ואילו LCP מודד מתי התוכן הראשי מוצג.
איך נקבע גודל הרכיב?
גודל הרכיב שמדווח ב-LCP הוא בדרך כלל הגודל שגלוי למשתמש באזור התצוגה. אם האלמנט נמשך מחוץ לאזור התצוגה, או שהוא חתוך או שיש בו overflow לא גלוי, החלקים האלה לא נלקחים בחשבון במסגרת גודל הרכיב.
לאלמנטים בתמונה שגודלם השתנה מהגודל הפנימי שלהם, הגודל שמדווח הוא הגודל הגלוי או הגודל הפנימי, הקטן מביניהם.
ברכיבי טקסט, LCP מתייחסת רק למלבן הקטן ביותר שיכול להכיל את כל צומתי הטקסט.
בכל האלמנטים, LCP לא מביא בחשבון שוליים, מרווחים או גבולות שהוחלו באמצעות CSS.
שלומתי מתבצע דיווח על מדד LCP?
דפי אינטרנט נטענים לעיתים קרובות בשלבים, וכתוצאה מכך, הרכיב הגדול ביותר בדף עשוי להשתנות במהלך הטעינה.
כדי להתמודד עם פוטנציאל השינוי הזה, הדפדפן שולח PerformanceEntry
מסוג largest-contentful-paint
שמזהה את הרכיב בעל התוכן הכי גדול
ברגע שהדפדפן יוצר את הפריים הראשון. אחרי העיבוד של הפריימים הבאים, הוא שולח PerformanceEntry
נוסף בכל פעם שהרכיב הגדול ביותר של תוכן עם תוכן משתנה.
לדוגמה, בדף עם טקסט ותמונה ראשית (Hero), הדפדפן עשוי לעבד בהתחלה רק את הטקסט, והדפדפן ישלח ערך largest-contentful-paint
שהמאפיין element
שלו מפנה ל-<p>
או ל-<h1>
. אחרי שמסתיימת הטעינה של התמונה הראשית, נשלחת רשומה שנייה של largest-contentful-paint
עם מאפיין element
שמתייחס ל-<img>
.
רכיב יכול להיחשב כרכיב הגדול ביותר המכיל תוכן רק אחרי שהוא עובר עיבוד והוא גלוי למשתמש. תמונות שעדיין לא נטענו לא נחשבות כ'מעובדות'. גם לא צמתים של טקסט שנעשה בהם שימוש בגופני אינטרנט במהלך התקופה של חסימת הגופנים.
במקרים כאלה, יכול להיות שהמערכת תדווח שרכיב קטן יותר הוא הרכיב הגדול ביותר עם תוכן, אבל ברגע שהרכיב הגדול יותר מסיים את העיבוד, נוצר PerformanceEntry
נוסף.
נוסף על טעינה מאוחרת של תמונות וגופנים, יכול להיות שבדף יתווסף רכיבים חדשים ל-DOM כשתוכן חדש יהיה זמין. אם אחד מהרכיבים החדשים האלה גדול יותר מהרכיב הקודם עם התוכן הגדול ביותר, נוצר PerformanceEntry
חדש.
אם מסירים את רכיב התוכן הגדול ביותר מאזור התצוגה, או אפילו מה-DOM, הוא נשאר רכיב התוכן הגדול ביותר, אלא אם מתבצע עיבוד של רכיב גדול יותר.
הדפדפן מפסיק לדווח על רשומות חדשות ברגע שהמשתמש יוצר אינטראקציה עם הדף (באמצעות הקשה, גלילה או לחיצה על מקשים), כי אינטראקציה של משתמש בדרך כלל משנה את התוכן שגלוי למשתמש (במיוחד בזמן גלילה).
למטרות ניתוח, יש לדווח רק על PerformanceEntry
שנשלחו לאחרונה לשירות ניתוח הנתונים.
זמן טעינה לעומת זמן רינדור
מטעמי אבטחה, חותמת הזמן של העיבוד של תמונות לא חושפת תמונות ממקורות שונים שאין להן את הכותרת Timing-Allow-Origin
. במקום זאת, רק זמן הטעינה שלהם, שממשקי API אחרים כבר חושפים, זמין.
המצב הזה עלול לגרום למצב בלתי אפשרי לכאורה, שבו ממשקי API לאינטרנט מדווחים על LCP לפני FCP. רק בגלל הגבלת האבטחה הזו, והיא לא מייצגת את מה שקורה באמת.
כשאפשר, מומלץ תמיד להגדיר את הכותרת Timing-Allow-Origin
כדי שהמדדים יהיו מדויקים יותר.
איך מטופלים שינויים בפריסת הרכיבים ובגודל שלהם?
כדי שתקורה של הביצועים בחישוב ובשליחה של ערכי ביצועים חדשים תהיה נמוכה, שינויים בגודל או במיקום של הרכיב לא יוצרים מועמדים חדשים ל-LCP. רק הגודל והמיקום הראשוניים של האלמנט באזור התצוגה מובאים בחשבון.
כלומר, יכול להיות שלא יתבצע דיווח על תמונות שמוצגות בהתחלה מחוץ למסך ואז עוברות למסך. זה גם אומר שרכיבים שעברו רינדור בהתחלה באזור התצוגה, ולאחר מכן נדחפים אל מחוץ לאזור התצוגה, עדיין מדווחים על הגודל הראשוני שלהם באזור התצוגה.
דוגמאות
הנה כמה דוגמאות למקרים שבהם ה-LCP מופיע במספר אתרים פופולריים:
בשני צירי הזמן האלה, הרכיב הגדול ביותר (מודגש בירוק) משתנה כשתוכן נטען. בדוגמה הראשונה, תוכן חדש מתווסף ל-DOM, ומשנה את הרכיב הגדול ביותר. בדוגמה השנייה הפריסה משתנה, תוך הסרת רכיב התוכן הקודם הגדול ביותר מאזור התצוגה.
במקרים רבים, תוכן שנטען מאוחר גדול יותר מהתוכן שכבר נמצא בדף, אבל זה לא בהכרח המצב. בשתי הדוגמאות הבאות אפשר לראות את ה-LCP שמתרחש לפני שהדף נטען במלואו.
בדוגמה הראשונה, הלוגו של Instagram נטען מוקדם יחסית והוא נשאר האלמנט הכי גדול גם כשמוסיפים תוכן אחר. בדוגמה של דף תוצאות החיפוש ב-Google, האלמנט הגדול ביותר הוא פסקה של טקסט שמוצגת לפני שאחת מהתמונות או הלוגו נטענים. מכיוון שכל תמונה בנפרד קטנה יותר מהפסקה הזו, היא נשארת המרכיב הגדול ביותר בתהליך הטעינה.
איך מודדים LCP
ניתן למדוד את ה-LCP במעבדה או בשדה, וזמין בכלים הבאים:
כלי שדה
- הדוח לגבי חוויית המשתמש ב-Chrome
- PageSpeed Insights
- Search Console (דוח מדדי הליבה לבדיקת חוויית המשתמש באתר)
- ספריית JavaScript ב-
web-vitals
כלי מעבדה
מדידת 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, צריך לכלול iframes. תת-מסגרות יכולות להשתמש ב-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 על ידי אנני סאליבן ב-performance.now() (2019)
יומן שינויים
מדי פעם מתגלים באגים בממשקי ה-API שמשמשים למדידת מדדים, ולפעמים גם בהגדרות של המדדים עצמם. כתוצאה מכך, לפעמים צריך לבצע שינויים, והם עשויים להופיע כשיפורים או רגרסיות בדוחות הפנימיים ובמרכזי הבקרה.
כדי לעזור לכם לנהל אותו, כל השינויים בהטמעה או בהגדרה של המדדים האלה מופיעים ביומן השינויים הזה.
אם יש לכם משוב לגבי המדדים האלה, אפשר לשלוח אותו בקבוצת Google בנושא Web-vitals-feedback.