שינויים לא צפויים בפריסה יכולה לשבש את חוויית המשתמש בדרכים רבות, החל מיגרמו להם לאבד את מקומם כשהם קוראים את הטקסט אם הטקסט זז בפתאומיות, ועד שהם לוחצים על הקישור או על הלחצן הלא נכונים. במקרים מסוימים, הדבר עלול לגרום לנזק חמור.
תנועה לא צפויה של תוכן הדף מתרחשת בדרך כלל כאשר משאבים נטענים באופן אסינכרוני או כאשר רכיבי DOM נוספים באופן דינמי לדף לפני תוכן קיים. הגורם לשינויי הפריסה עשוי להיות תמונות או סרטונים שהמידות שלהם לא ידועות, גופנים שגודלם משתנה או שגודלם משתנה בהתאם לגודל המקורי שלהם, או מודעות או ווידג'טים של צד שלישי שגודלם משתנה באופן דינמי.
ההבדלים בין אופן התפקוד של אתר בפיתוח לבין האופן שבו המשתמשים בו חווים אותו, מחמירים את הבעיה הזו. לדוגמה:
- לעיתים קרובות, תוכן בהתאמה אישית או תוכן של צד שלישי מתנהג באופן שונה בפיתוח ובייצור.
- לרוב, תמונות הבדיקה כבר נשמרות במטמון הדפדפן של המפתח, אבל אצל משתמש הקצה הטעינה שלהן נמשכת זמן רב יותר.
- קריאות ל-API שרצות באופן מקומי הן לעיתים קרובות מהירות כל כך עד שעיכובים לא מורגשים בפיתוח יכולים להפוך באופן משמעותי בייצור.
המדד Cumulative Layout Shift (CLS) עוזר לך לטפל בבעיה הזו באמצעות מדידת התדירות שבה היא מתרחשת בקרב משתמשים אמיתיים.
מה זה CLS?
CLS הוא מדד של הרצף הגדול ביותר של ציוני תנודות בפריסה לכל שינוי פריסה לא צפוי שמתרחש במהלך כל מחזור החיים של דף.
שינוי פריסה מתרחש בכל פעם שרכיב גלוי משנה את המיקום שלו ממסגרת אחת שמעובדת למסגרת שעברה עיבוד. (פרטים על האופן שבו מחושבים ציונים של תזוזות בפריסות נפרדות מוסברים בהמשך המדריך הזה).
רצף של שינויי פריסה, שנקרא חלון סשן, קורה כאשר שינוי פריסה אחד או יותר מתרחש ברצף מהיר, עם פחות משנייה אחת בין כל משמרת, ועד 5 שניות בכל משך החלון הכולל.
הרצף הגדול ביותר הוא חלון הסשן עם הציון המצטבר המקסימלי של כל שינויי הפריסה בחלון הזה.
מהו ציון CLS טוב?
כדי לספק חוויית משתמש טובה, אתרים צריכים לשמור על ציון CLS של 0.1 או פחות. כדי לוודא שאתם עומדים ביעד הזה עבור רוב המשתמשים, סף טוב למדידה הוא האחוזון ה-75 של טעינות דפים, המפולחים במכשירים ניידים ובמחשבים.
למידע נוסף על המחקר והמתודולוגיה שעומדים מאחורי ההמלצה הזו, ראו הגדרת ערכי הסף של מדדי הליבה לבדיקת חוויית המשתמש באתר.
פירוט של שינויים בפריסה
שינויי הפריסה מוגדרים על ידי 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
.
דוגמאות
הדוגמה הבאה ממחישה איך הוספת תוכן לרכיב קיים משפיעה על הציון של שינוי הפריסה:
בדוגמה הזו, גודל התיבה האפורה משתנה, אבל מיקום ההתחלה שלה לא משתנה ולכן היא לא רכיב לא יציב.
הלחצן "לחצו עלי!" לא היה קודם ב-DOM, כך שגם מיקום ההתחלה שלו לא משתנה.
עם זאת, מיקום ההתחלה של התיבה הירוקה משתנה, אך מכיוון שהיא הועברה באופן חלקי מאזור התצוגה, האזור הבלתי נראה לא נלקח בחשבון בחישוב שבר ההשפעה. איחוד האזורים הגלויים לתיבה הירוקה בשתי המסגרות (איור באמצעות המלבן האדום והמקווקו) זהה לשטח של התיבה הירוקה במסגרת הראשונה — 50% מאזור התצוגה. שבר ההשפעה הוא 0.5
.
שבר המרחק מיוצג באמצעות החץ הסגול. התיבה הירוקה זזה כלפי מטה בכ-14% מאזור התצוגה, כך ששבר המרחק הוא 0.14
.
הציון של שינוי הפריסה הוא 0.5 x 0.14 = 0.07
.
בדוגמה הבאה אפשר לראות איך מספר רכיבים לא יציבים משפיעים על הציון של שינוי הפריסה של דף:
בפריים הראשון שבתמונה הקודמת, מופיעות ארבע תוצאות של בקשת API לבעלי חיים, מסודרת בסדר אלפביתי. במסגרת השנייה, נוספות עוד תוצאות לרשימה הממוינת.
הפריט הראשון ברשימה ("חתול") לא משנה את מיקום ההתחלה שלו בין פריימים, ולכן הוא יציב. באופן דומה, הפריטים החדשים שנוספו לרשימה לא היו לפני כן ב-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()
. - כדי להזיז רכיבים, יש להימנע משינוי המאפיינים
top
,right
,bottom
אוleft
, ולהשתמש במקומם ב-transform: translate()
.
איך מודדים CLS
אפשר למדוד את CLS בשיעור ה-Lab או בשדה, והוא זמין בכלים הבאים:
כלים לשטח
- חוויית המשתמש ב-Chrome דיווח
- PageSpeed Insights
- Search Console (מדדי הליבה לבדיקת חוויית המשתמש באתר) בדוח)
- ספריית JavaScript של
web-vitals
כלים לשיעור 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
הלא צפויות האלה לסשנים ולחשב את ערך הסשן המקסימלי. בקוד המקור של ספריית JavaScript web vitals
יש הטמעה של חומר עזר בנושא אופן החישוב של CLS.
ברוב המקרים, ערך ה-CLS הנוכחי בזמן הסרת הדף הוא ערך ה-CLS הסופי של הדף, אבל יש מספר חריגים חשובים, כפי שמצוין בקטע הבא. ספריית ה-JavaScript web vitals
מתייחסת לרכיבים האלה עד כמה שאפשר, במגבלות של ממשקי ה-API באינטרנט.
ההבדלים בין המדד לבין ה-API
- אם דף נטען ברקע, או אם הוא מופיע ברקע לפני שהדפדפן צובע תוכן כלשהו, אסור לדווח על ערך CLS.
- אם דף משוחזר מהמטמון לדף הקודם/הבא, ערך ה-CLS שלו צריך לאפס את ערך ה-CLS, כי המשתמשים חווים זאת כביקור בדף נפרד.
- ה-API לא מדווח על רשומות
layout-shift
לגבי שינויים שמתרחשים בתוך מסגרות iframe, אבל המדד כן מתייחס לחוויית המשתמש בדף. זה יכול להיות הבדל בין CrUX ל-RUM. כדי למדוד בצורה נכונה את ה-CLS, כדאי להתייחס אליהם. תמונות משנה יכולות להשתמש ב-API כדי לדווח על רשומותlayout-shift
שלהן למסגרת ההורה לצורך צבירה.
בנוסף לחריגים האלה, ל-CLS יש קצת יותר מורכבות כי הוא מודד את כל משך החיים של דף:
- המשתמשים עשויים להשאיר כרטיסייה פתוחה למשך זמן רב – ימים, שבועות או חודשים. למעשה, יכול להיות שלעולם לא יסגרו כרטיסייה.
- במערכות הפעלה לנייד, דפדפנים בדרך כלל לא מריצים קריאות חוזרות (callbacks) של דפים שנטענו עבור כרטיסיות ברקע, מה שמקשה על דיווח ה"סופי" עם ערך מסוים.
כדי לטפל במקרים כאלה, צריך לדווח על CLS בכל פעם שדף נמצא ברקע – בנוסף לכל זמן שבו מתבצעת טעינה שלו (האירוע visibilitychange
מכסה את שני התרחישים האלה). לאחר מכן, מערכות ניתוח הנתונים שמקבלות את הנתונים האלה יצטרכו לחשב את ערך ה-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.
מקורות מידע נוספים
- המדריך של Google Publisher Tag לגבי צמצום של שינוי הפריסה
- הסבר על Cumulative Layout Shift מאת Anie Sullivan וSteve Kobes ב-#PerfMatters (2020)
יומן שינויים
מדי פעם מתגלים באגים בממשקי ה-API שמשמשים למדידת מדדים, ולפעמים גם בהגדרות של המדדים עצמם. כתוצאה מכך, לפעמים צריך לבצע שינויים, והשינויים יכולים להופיע כשיפורים או כרגרסיות בדוחות הפנימיים ובלוחות הבקרה.
כדי לעזור לכם לנהל את זה, כל השינויים בהטמעה או בהגדרה של המדדים האלה יופיעו ביומן השינויים הזה.
אם יש לכם משוב על המדדים האלה, אתם יכולים לשלוח אותו בקבוצת Google בנושא web-vitals-feedback.