אופטימיזציה של Largest Contentful Paint (LCP)

מדריך מפורט איך לפרק את ה-LCP ולזהות תחומים עיקריים שצריך לשפר.

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

כדי לספק חוויית משתמש טובה, אתרים צריכים להקפיד על צריכת LCP של 2.5 שניות או פחות ב-75% מהביקורים בדפים לפחות.

ערכי LCP טובים הם 2.5 שניות לכל היותר, ערכים נמוכים הם גדולים מ-4.0 שניות וכל מה שביניהם צריך לשפר
ערך LCP טוב הוא 2.5 שניות לכל היותר.

יש כמה גורמים שיכולים להשפיע על המהירות שבה הדפדפן יכול לטעון ולעבד דף אינטרנט. עיכובים בכל אחד מהם יכולים להשפיע באופן משמעותי על LCP.

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

הסבר על מדד ה-LCP

לפני אופטימיזציה של LCP, מפתחים צריכים להבין אם יש להם אפילו בעיית LCP, ומה היקף של כל בעיה כזו.

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

נתוני LCP שמבוססים על משתמשים אמיתיים יכולים להופיע בכלים של Real User Monitoring (RUM) שהותקנו באתר או בדוח על חוויית המשתמש ב-Chrome (CrUX) שאוסף נתונים אנונימיים ממשתמשי Chrome אמיתיים במיליוני אתרים.

שימוש בנתוני CrUX LCP של PageSpeed Insights

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

נתוני CrUX מוצגים ב-PageSpeed Insights
נתוני CrUX מוצגים ב-PageSpeed Insights.

הכלי PageSpeed Insights מציג עד ארבעה נתוני CrUX שונים:

  • נתוני נייד של כתובת ה-URL הזו
  • נתוני מחשב עבור כתובת ה-URL הזו
  • נתוני נייד של כל המקור
  • נתוני מחשב לגבי כל המקור

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

מדדים של PageSpeed חוזרים לנתונים ברמת המקור שבהם אין נתונים ברמת כתובת ה-URL
אם ל-PageSpeed Insights אין נתונים ברמת כתובת ה-URL, היא מציגה נתונים ברמת המקור.

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

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

שימוש במדדים משלימים של PageSpeed Insights ל-CrUX

משתמשים שרוצים לבצע אופטימיזציה ל-LCP צריכים להשתמש גם בתזמונים של First Contentful Paint (FCP) ו-Time to First Byte (TTFB), שהם מדדי אבחון טובים שיכולים לספק תובנות חשובות לגבי LCP.

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

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

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

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

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

שימוש בנתוני PageSpeed Insights Lighthouse

בקטע Lighthouse ב-PageSpeed Insights יש כמה הנחיות לשיפור LCP, אבל קודם צריך לבדוק אם מדד ה-LCP שניתן תואם באופן כללי לנתוני משתמשים אמיתיים שסופקו על ידי CrUX. אם אין הסכמה בין Lighthouse ומ-CrUX, סביר להניח ש-CrUX מספק תמונה מדויקת יותר של חוויית המשתמש שלכם. לפני שמבצעים פעולה על הנתונים, חשוב לוודא שנתוני CrUX הם של הדף שלכם, ולא של המקור המלא.

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

הזדמנויות ואבחון LCP ב-Lighthouse
אבחון והצעות לשיפור LCP של Lighthouse.

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

שלבי LCP ב-Lighthouse
פירוט של אלמנטים מסוג LCP על ידי Lighthouse.

בהמשך נתעמק בחלקי המשנה האלה.

פירוט LCP

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

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

רוב טעינות הדפים כוללות בדרך כלל כמה בקשות רשת, אבל כדי לזהות הזדמנויות לשיפור LCP, כדאי להתחיל בבדיקת שתיים בלבד:

  1. מסמך ה-HTML הראשוני
  2. משאב ה-LCP (אם רלוונטי)

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

כדי לזהות את משאב ה-LCP, אפשר להשתמש בכלים למפתחים (כמו PageSpeed Insights שהסברנו קודם, Chrome DevTools או WebPageTest) כדי לקבוע את רכיב ה-LCP. משם תוכלו להתאים את כתובת ה-URL (שוב, אם רלוונטי) שנטענה על ידי הרכיב בWaterfall של רשת, בכל המשאבים שנטענו על ידי הדף.

לדוגמה, באיור הבא מוצגים המשאבים האלה שמודגשים בתרשים מפל רשת של רשת מטעינת דף אופיינית, שבה רכיב ה-LCP דורש רינדור תמונה.

Waterfall של רשת עם הדגשה של משאבי HTML ו-LCP
תרשים מפל שמראה את זמני הטעינה של HTML של דף אינטרנט והמשאבים שדרושים ל-LCP.

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

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

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

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

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

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

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

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

הסיבה לכך היא שבדף הזה, רכיב ה-LCP מוסתר עד שקוד ה-JavaScript מסתיים, ולאחר מכן הכול נחשף בבת אחת.

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

זמני משנה אופטימליים

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

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

חלק משנה LCP אחוז LCP
זמן עד בייט ראשון ~40%
השהיה של טעינת משאבים <10%
משך הזמן של טעינת משאבים ~40%
עיכוב בעיבוד הרכיב <10%
TOTAL 100%

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

אחת הדרכים הטובות לחשב את הפירוט של זמן LCP היא:

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

איך לבצע אופטימיזציה של כל חלק

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

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

1. למנוע עיכוב בטעינת משאבים.

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

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

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

באופן כללי, יש שני גורמים שמשפיעים על המהירות שבה משאב LCP יכול להיטען:

  • כשהמשאב מתגלה.
  • איזו עדיפות ניתנת למשאב.

ביצוע אופטימיזציה כשהמשאב מאותר

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

  • רכיב ה-LCP הוא רכיב <img>, והמאפיינים src או srcset שלו נמצאים בתגי העיצוב הראשוניים של ה-HTML.
  • לרכיב ה-LCP נדרשת תמונת רקע של CSS, אבל התמונה הזו נטענת מראש באמצעות <link rel="preload"> בתגי העיצוב של HTML (או באמצעות כותרת Link).
  • רכיב ה-LCP הוא צומת טקסט שמחייב עיבוד של גופן אינטרנט, והגופן נטען באמצעות <link rel="preload"> בתגי העיצוב של HTML (או באמצעות כותרת Link).

הנה כמה דוגמאות שבהן לא ניתן למצוא את משאב ה-LCP מסריקת התגובה של מסמך ה-HTML:

  • רכיב ה-LCP הוא רכיב <img> שמתווסף באופן דינמי לדף באמצעות JavaScript.
  • רכיב ה-LCP נטען באופן מדורג עם ספריית JavaScript שמסתירת את מאפייני src או srcset שלו (בדרך כלל זה data-src או data-srcset).
  • רכיב ה-LCP מחייב תמונת רקע של CSS.

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

כדי למנוע עיכוב מיותר בטעינת משאבים, משאב ה-LCP צריך להיות גלוי ממקור ה-HTML. במקרים שבהם יש הפניה למשאב רק מקובץ CSS או JavaScript חיצוני, צריך לטעון מראש את משאב ה-LCP עם עדיפות שליפה גבוהה. לדוגמה:

<!-- Load the stylesheet that will reference the LCP image. -->
<link rel="stylesheet" href="/path/to/styles.css">

<!-- Preload the LCP image with a high fetchpriority so it starts loading with the stylesheet. -->
<link rel="preload" fetchpriority="high" as="image" href="/path/to/hero-image.webp" type="image/webp">

ביצוע אופטימיזציה של העדיפות שניתנה למשאב

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

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

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

<img fetchpriority="high" src="/path/to/hero-image.webp">

כדאי להגדיר את fetchpriority="high" ברכיב <img> אם סביר להניח שזהו רכיב ה-LCP של הדף. עם זאת, הגדרת עדיפות גבוהה ליותר מתמונה אחת או שתיים, הופכת את הגדרת העדיפות לא מועילה להפחתת LCP.

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

<img fetchpriority="low" src="/path/to/carousel-slide-3.webp">

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

אחרי שמבצעים אופטימיזציה של עדיפות משאבי ה-LCP וזמן הגילוי, ה-Waterfall של הרשת אמור להיראות כך (כשמשאב ה-LCP מתחיל באותו זמן כמו המשאב הראשון):

תרשים Waterfall של רשת שמציג את משאב ה-LCP שמתחיל עכשיו באותו זמן כמו המשאב הראשון
משאב ה-LCP מתחיל עכשיו להיטען באותו זמן כמו גיליון הסגנונות.

2. ביטול עיכוב בעיבוד הרכיב

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

הסיבה העיקרית שלא ניתן יהיה לעבד את רכיב ה-LCP מיד לאחר סיום הטעינה של המשאב היא אם הרינדור נחסם מסיבה אחרת:

  • העיבוד של הדף כולו חסום בגלל גיליונות סגנונות או סקריפטים סינכרוניים ב-<head> שעדיין נטענים.
  • משאב ה-LCP הסתיים, אבל רכיב ה-LCP עדיין לא נוסף ל-DOM (הוא ממתין לטעינה של קוד JavaScript מסוים).
  • הרכיב מוסתר על ידי קוד אחר, כמו ספרייה של בדיקת A/B שעדיין קובעת באיזה ניסוי המשתמש צריך להשתתף.
  • ה-thread הראשי חסום בגלל משימות ארוכות, ועבודות העיבוד צריכות להמתין עד שהמשימות הארוכות האלה יסתיימו.

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

מזעור גיליונות סגנונות שחוסמים עיבוד או מכילים אותם בשורה

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

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

כדי לפתור את הבעיה, עומדות לרשותכם האפשרויות הבאות:

  • להטביע את גיליון הסגנונות ב-HTML כדי להימנע מבקשת הרשת הנוספת; או
  • להקטין את גיליון הסגנונות.

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

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

הנה כמה המלצות להקטנת הגודל של גיליון הסגנונות:

דחייה או מוטבעת של JavaScript שחוסם עיבוד

כמעט אין צורך להוסיף סקריפטים סינכרוניים (סקריפטים ללא המאפיינים async או defer) אל <head> הדפים, והפעולה הזו כמעט תמיד תשפיע על הביצועים.

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

מה אסור לעשות
<head>
  <script src="/path/to/main.js"></script>
</head>
מה מותר לעשות
<head>
  <script>
    // Inline script contents directly in the HTML.
    // IMPORTANT: only do this for very small scripts.
  </script>
</head>

שימוש ברינדור בצד השרת

רינדור בצד השרת (SSR) הוא התהליך של הרצת לוגיקת האפליקציה בצד הלקוח בשרת ותגובה לבקשות של מסמכי HTML עם תגי העיצוב המלאים של ה-HTML.

מבחינת אופטימיזציה של LCP, יש שני יתרון מרכזי של SSR:

  • משאבי התמונות יהיו גלויים ממקור ה-HTML (כפי שמתואר בשלב 1 קודם).
  • תוכן הדף לא ידרוש בקשות JavaScript נוספות לסיום לפני שניתן יהיה לעבד אותו.

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

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

להפריד בין משימות ארוכות

גם אם פעלת לפי העצה הקודמת, וקוד ה-JavaScript לא חוסם רינדור וגם לא אחראי לעיבוד הרכיבים, הוא עדיין עלול לעכב את LCP.

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

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

3. קיצור משך הזמן של טעינת המשאבים

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

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

הקטנת המשאב

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

הקטנת המרחק שהמשאב צריך לעבור

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

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

הפחתת התחרות על רוחב הפס ברשת

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

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

ביטול מוחלט של זמן הרשת

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

אם משאב ה-LCP הוא גופן אינטרנט, בנוסף להקטנת גופן האינטרנט, צריך לבדוק אם צריך לחסום את הרינדור בטעינת המשאב של גופן האינטרנט. אם מגדירים font-display ערך שאינו auto או block, הטקסט תמיד יהיה גלוי במהלך הטעינה ו-LCP לא ייחסם בבקשת רשת נוספת.

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

4. הפחתת הזמן בייט ראשון

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

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

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

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

מעקב אחרי פירוט LCP ב-JavaScript

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

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

לדוגמה, בצילום המסך הבא נעשה שימוש בשיטה performance.measure() מ-User Timing API כדי להוסיף עמודות אל המסלול Timings בחלונית הביצועים של כלי הפיתוח ב-Chrome.

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

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

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

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

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

שתי האפשרויות החזותיות האלה נוצרו באמצעות הקוד הבא:

const LCP_SUB_PARTS = [
  'Time to first byte',
  'Resource load delay',
  'Resource load duration',
  'Element render delay',
];

new PerformanceObserver((list) => {
  const lcpEntry = list.getEntries().at(-1);
  const navEntry = performance.getEntriesByType('navigation')[0];
  const lcpResEntry = performance
    .getEntriesByType('resource')
    .filter((e) => e.name === lcpEntry.url)[0];

  // Ignore LCP entries that aren't images to reduce DevTools noise.
  // Comment this line out if you want to include text entries.
  if (!lcpEntry.url) return;

  // Compute the start and end times of each LCP sub-part.
  // WARNING! If your LCP resource is loaded cross-origin, make sure to add
  // the `Timing-Allow-Origin` (TAO) header to get the most accurate results.
  const ttfb = navEntry.responseStart;
  const lcpRequestStart = Math.max(
    ttfb,
    // Prefer `requestStart` (if TOA is set), otherwise use `startTime`.
    lcpResEntry ? lcpResEntry.requestStart || lcpResEntry.startTime : 0
  );
  const lcpResponseEnd = Math.max(
    lcpRequestStart,
    lcpResEntry ? lcpResEntry.responseEnd : 0
  );
  const lcpRenderTime = Math.max(
    lcpResponseEnd,
    // Use LCP startTime (the final LCP time) because there are sometimes
    // slight differences between loadTime/renderTime and startTime
    // due to rounding precision.
    lcpEntry ? lcpEntry.startTime : 0
  );

  // Clear previous measures before making new ones.
  // Note: due to a bug, this doesn't work in Chrome DevTools.
  LCP_SUB_PARTS.forEach((part) => performance.clearMeasures(part));

  // Create measures for each LCP sub-part for easier
  // visualization in the Chrome DevTools Performance panel.
  const lcpSubPartMeasures = [
    performance.measure(LCP_SUB_PARTS[0], {
      start: 0,
      end: ttfb,
    }),
    performance.measure(LCP_SUB_PARTS[1], {
      start: ttfb,
      end: lcpRequestStart,
    }),
    performance.measure(LCP_SUB_PARTS[2], {
      start: lcpRequestStart,
      end: lcpResponseEnd,
    }),
    performance.measure(LCP_SUB_PARTS[3], {
      start: lcpResponseEnd,
      end: lcpRenderTime,
    }),
  ];

  // Log helpful debug information to the console.
  console.log('LCP value: ', lcpRenderTime);
  console.log('LCP element: ', lcpEntry.element, lcpEntry.url);
  console.table(
    lcpSubPartMeasures.map((measure) => ({
      'LCP sub-part': measure.name,
      'Time (ms)': measure.duration,
      '% of LCP': `${
        Math.round((1000 * measure.duration) / lcpRenderTime) / 10
      }%`,
    }))
  );
}).observe({type: 'largest-contentful-paint', buffered: true});

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

מעקב אחרי פירוטי LCP באמצעות תוסף Web Vitals

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

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

סיכום

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

ברמה הכללית, אפשר לסכם את האופטימיזציה של LCP בארבעה שלבים:

  1. מוודאים שמשאב ה-LCP מתחיל להיטען מוקדם ככל האפשר.
  2. מוודאים שרכיב ה-LCP יכול לעבור רינדור ברגע שטעינת המשאב שלו מסתיימת.
  3. הפחתת זמן הטעינה של משאב ה-LCP עד כמה שאפשר, מבלי לגרוע מהאיכות.
  4. יש לספק את מסמך ה-HTML הראשוני במהירות האפשרית.

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