Cumulative Layout Shift (CLS)

תמיכה בדפדפן

  • 77
  • 79
  • x
  • x

מקור

Cumulative Layout Shift (CLS) הוא מדד ליבה לבדיקת חוויית המשתמש באתר ויציב. זהו מדד חשוב שמתמקד במשתמשים למדידת יציבות חזותית, כי הוא עוזר לכמת את התדירות שבה משתמשים חווים תנודות בלתי צפויות בפריסה. ערך CLS נמוך עוזר לוודא שהדף מושך ומעניין.

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

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

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

ההבדלים בין אופן הפעולה של אתר בתהליך הפיתוח לבין האופן שבו המשתמשים חווים אותו, הופכים את הבעיה להחמרה. לדוגמה:

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

המדד Cumulative Layout Shift (CLS) יכול לעזור לכם לטפל בבעיה הזו ולמדוד את התדירות שבה היא מתרחשת אצל משתמשים אמיתיים.

מה זה CLS?

CLS הוא מדד של הרצף הגדול ביותר של ציוני שינויים בפריסה עבור כל שינוי פריסה לא צפוי שמתרחש במהלך משך החיים של דף.

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

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

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

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

מהו ציון CLS טוב?

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

ערכי CLS טובים הם 0.1 או פחות, ערכים נמוכים גבוהים מ-0.25 וכל דבר שביניהם דורש שיפור
ערכי ה-CLS הטובים הם 0.1 או פחות. הערכים הנמוכים גדולים מ-0.25.

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

שינויי פריסה מפורטים

שינויי הפריסה מוגדרים על ידי Layout Instability API, שמדווח על רשומות layout-shift בכל פעם שרכיב גלוי באזור התצוגה משנה את מיקום ההתחלה שלו (למשל, המיקום העליון והשמאלי במצב הכתיבה שמוגדר כברירת מחדל) בין שתי פריימים. רכיבים שמיקומי ההתחלה שלהם משתנים כרכיבים לא יציבים.

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

הציון של שינוי הפריסה

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

layout shift score = impact fraction * distance fraction

שבר ההשפעה

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

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

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

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

שבר מרחק

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

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

בדוגמה הזו, המאפיין הגדול ביותר של אזור התצוגה הוא הגובה, והרכיב הלא יציב זז ב-25% מגובה אזור התצוגה, וכך שבר המרחק 0.25.

שבר ההשפעה של 0.75 וחלקי המרחק של 0.25 יוצרים ציון של 0.75 * 0.25 = 0.1875 לשינוי פריסה.

דוגמאות

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

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

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

הלחצן 'Click Me! ' לא היה ב-DOM בעבר, ולכן גם מיקום ההתחלה שלו לא משתנה.

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

שבר המרחק מתואר על ידי החץ הכחול. התיבה הירוקה הועברה למטה בכ-14% מאזור התצוגה, כך שקטע המרחק הוא 0.14.

הציון של שינוי הפריסה הוא 0.5 x 0.14 = 0.07.

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

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

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

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

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

הציון של שינוי הפריסה הוא 0.60 x 0.3 = 0.18.

שינויים צפויים בפריסה לעומת שינויים לא צפויים בפריסה

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

שינויי פריסה ביוזמת המשתמש

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

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

בהפרשי פריסה שמתרחשים בתוך 500 אלפיות השנייה לאחר קלט של משתמשים, הדגל hadRecentInput יהיה מוגדר, כך שתוכלו להחריג אותם מהחישובים.

אנימציות ומעברים

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

הקפידו לכבד את הגדרות הדפדפן של prefers-reduced-motion, כי אנימציה עלולה לגרום לבעיות בתקינות או בתשומת הלב של חלק מהמבקרים באתר.

מאפיין ה-CSS transform מאפשר להוסיף אנימציה לרכיבים בלי להפעיל שינויי פריסה:

  • במקום לשנות את המאפיינים height ו-width, משתמשים ב-transform: scale().
  • כדי להזיז רכיבים, צריך להשתמש ב-transform: translate() במקום לשנות את המאפיינים top, right, bottom או left.

איך מודדים CLS

אפשר למדוד את ה-CLS בשיעור Lab או בשדה, והוא זמין בכלים הבאים.

כלי שדה

כלי מעבדה

מדידת שינויים בפריסה ב-JavaScript

כדי למדוד שינויים בפריסה ב-JavaScript, יש להשתמש ב-Layout Instability API.

הדוגמה הבאה מציגה איך ליצור PerformanceObserver כדי לרשום רשומות layout-shift במסוף:

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('Layout shift:', entry);
  }
}).observe({type: 'layout-shift', buffered: true});

מדידת CLS ב-JavaScript

כדי למדוד CLS ב-JavaScript, צריך לקבץ את רשומות layout-shift הלא צפויות שרשמתם לסשנים ולחשב את ערך הסשן המקסימלי. להטמעה של קובצי עזר, אפשר לעיין בקוד המקור של ספריית web vitals JavaScript.

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

הבדלים בין המדד לבין ה-API

  • אם דף נטען ברקע או אם הוא מופיע ברקע לפני שהדפדפן מצייר תוכן, לא אמור להיות דיווח על ערך CLS.
  • במקרה שדף שוחזר ממטמון לדף הקודם או להעברה, יש לאפס את ערך ה-CLS שלו לאפס כי המשתמשים חווים זאת כביקור ייחודי בדף.
  • ה-API לא מדווח על רשומות layout-shift לתנודות שמתרחשות בתוך מסגרות iframe, אבל המדד כן מדווח כי הן חלק מחוויית המשתמש בדף. המידע הזה יכול להבדיל בין CrUX ל-RUM. כדי למדוד את נתוני ה-CLS בצורה תקינה, צריך לכלול iframes. אפשר להשתמש ב-API במסגרות משנה כדי לדווח על רשומות layout-shift שלהן למסגרת ההורה לצורך צבירה.

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

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

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

במקום לזכור בעל-פה ולהתמודד עם כל המקרים האלה בעצמכם, מפתחים יכולים להשתמש בספריית JavaScript web-vitals כדי למדוד CLS, שמביא בחשבון את כל מה שצוין כאן, מלבד מקרה ה-iframe:

import {onCLS} from 'web-vitals';

// Measure and log CLS in all situations
// where it needs to be reported.
onCLS(console.log);

איך לשפר את ה-CLS

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

משאבים נוספים

יומן שינויים

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

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

אם יש לכם משוב לגבי המדדים האלה, אפשר לשלוח אותו בקבוצת Google בנושא Web-vitals-feedback.