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

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

תאריך פרסום: 30 באפריל 2020

המהירות שבה נטען רכיב התוכן הכי גדול (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 שמבוססים על משתמשים אמיתיים באמצעות כלים למעקב אחר משתמשים אמיתיים (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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

חלוקה של משימות ארוכות

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

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

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

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

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

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

הקטנת המשאב

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

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

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

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

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

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

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

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

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

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

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

4. צמצום הזמן לקבלת בייט התגובה הראשון (TTFB)

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

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

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

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

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

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

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

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

מדדים של &#39;תזמון משתמש&#39; של קטגוריות המשנה 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 באמצעות כלי הפיתוח ל-Chrome

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

תזמוני חלקי משנה של LCP בחלונית הביצועים של כלי הפיתוח ל-Chrome
תזמוני חלקי משנה של LCP בחלונית הביצועים של כלי הפיתוח ל-Chrome.

סיכום

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

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

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

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