אופטימיזציה של 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 לגבי משתמשים אמיתיים, צריך לבחון את החוויה של משתמשים אמיתיים, ולא לראות מה מראה כלי מבוסס מעבדה כמו Lighthouse או בדיקות מקומיות. הכלים האלה במעבדה יכולים לספק הרבה מידע שיכול להסביר למשתמשים ולעזור בשיפור ה-LCP, אבל חשוב לזכור שבדיקות מעבדה לא תמיד משקפות בהכרח את החוויה של המשתמשים.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

אם יש הפרש גדול בין TTFB ל-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
אבחון של Lighthouse והצעות לשיפור LCP.

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

שלבי LCP ב-Lighthouse
פירוט רכיבי LCP ב-Lighthouse.

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

פירוט LCP

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

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

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

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

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

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

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

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

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

Time to First Byte (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 מתחיל להיטען מאוחר יותר מהמשאב הראשון, אז יש הזדמנות לשיפור.

תרשים מפל מים של רשת שמציג את משאב ה-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 מתחיל באותו זמן כמו המשאב הראשון):

תרשים מפל מים של רשת שמציג את משאב ה-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 הוא שנדרש זמן עיבוד נוסף של השרת, שעלול להאט את TTFB. עם זאת, בדרך כלל משתלם לך לעשות זאת, כי זמני העיבוד של השרת הם בשליטתך, ואילו יכולות הרשת והמכשיר של המשתמשים לא קשורות אליך.

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

פיצול משימות ארוכות

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

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

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

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

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

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

הקטנת גודל המשאב

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

לצמצם את המרחק של המשאב

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

בנוסף להמחשת חלקי המשנה של ה-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
בחלונית המסוף של התוסף Web Vitals מוצג פירוט של נתוני ה-LCP.

סיכום

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

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

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

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