ניפוי באגים שינויים בפריסה

איך לזהות ולתקן שינויים בפריסה.

קייטי המפניוס
קייטי המפניוס

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

כלים

API של אי יציבות בפריסה

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

Usage

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

let cls = 0;
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

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

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

המידע על השינויים בפריסה מדווח באמצעות שילוב של שני ממשקי API: הממשק LayoutShift ו-LayoutShiftAttribution. בחלקים הבאים מוסבר בהרחבה על כל אחד מהממשקים האלה.

LayoutShift

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

duration: 0
entryType: "layout-shift"
hadRecentInput: false
lastInputTime: 0
name: ""
sources: (3) [LayoutShiftAttribution, LayoutShiftAttribution, LayoutShiftAttribution]
startTime: 11317.934999999125
value: 0.17508567530168798

הרשומה שלמעלה מציינת שינוי פריסה שבמהלכו מיקום של שלושה רכיבי DOM השתנה. הציון של שינוי הפריסה של שינוי הפריסה הספציפי הזה היה 0.175.

אלה המאפיינים של מכונה LayoutShift הרלוונטיים ביותר לניפוי באגים בשינויי פריסה:

מאפיין (property) תיאור
sources הנכס sources מציג את רכיבי ה-DOM שהועברו בזמן שינוי הפריסה. מערך זה יכול להכיל עד חמישה מקורות. במקרה שיש יותר מחמישה רכיבים שמושפעים משינוי הפריסה, חמשת המקורות הגדולים ביותר (כפי שנמדדים על סמך ההשפעה על יציבות הפריסה) מדווחים. המידע הזה מדווח באמצעות הממשק LayoutShiftAttribution (הסבר מפורט בהמשך).
value הנכס value מדווח על הציון של שינוי בפריסה של שינוי פריסה ספציפי.
hadRecentInput המאפיין hadRecentInput מציין אם התרחש שינוי בפריסה בתוך 500 אלפיות השנייה לאחר קלט של משתמשים.
startTime המאפיין startTime מציין מתי התרחש שינוי בפריסה. הערך startTime מצוין באלפיות השנייה והנמדד ביחס לזמן שבו התחילה טעינת הדף.
duration המאפיין duration תמיד יוגדר כ-0. הנכס הזה עובר בירושה מהממשק PerformanceEntry (הממשק LayoutShift מרחיב את הממשק PerformanceEntry). עם זאת, הקונספט של משך זמן לא חל על אירועים של שינוי פריסה, ולכן הוא מוגדר לערך 0. מידע נוסף על הממשק של PerformanceEntry זמין בspec.

LayoutShiftAttribution

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

לדוגמה, קובץ ה-JSON שבהמשך תואם לשינוי פריסה עם מקור אחד: המעבר למטה של רכיב ה-DOM <div id='banner'> מ-y: 76 ל-y:246.

// ...
  "sources": [
    {
      "node": "div#banner",
      "previousRect": {
        "x": 311,
        "y": 76,
        "width": 4,
        "height": 18,
        "top": 76,
        "right": 315,
        "bottom": 94,
        "left": 311
      },
      "currentRect": {
        "x": 311,
        "y": 246,
        "width": 4,
        "height": 18,
        "top": 246,
        "right": 315,
        "bottom": 264,
        "left": 311
      }
    }
  ]

המאפיין node מזהה את רכיב ה-HTML שהשתנה. העברת העכבר על המאפיין הזה בכלי הפיתוח מדגישה את רכיב הדף המתאים.

המאפיינים previousRect ו-currentRect מדווחים על הגודל והמיקום של הצומת.

  • הקואורדינטות x ו-y מדווחות על קואורדינטת ה-x וקואורדינטת ה-Y בהתאמה לפינה השמאלית העליונה של הרכיב
  • המאפיינים width ו-height מדווחים על הרוחב והגובה של הרכיב, בהתאמה.
  • המאפיינים top, right, bottom ו-left מדווחים על ערכי הקואורדינטות של x או y שתואמים לקצה הנתון של הרכיב. במילים אחרות, הערך של top שווה ל-y; הערך של bottom שווה ל-y+height.

אם כל המאפיינים של previousRect מוגדרים ל-0, המשמעות היא שהרכיב הועבר לתצוגה. אם כל המאפיינים של currentRect מוגדרים ל-0, המשמעות היא שהאלמנט הועבר אל מחוץ לאזור התצוגה.

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

דוגמה ראשונה

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

דוגמה שמראה שינוי בפריסה שנגרם משינוי במאפייני הרכיב

דוגמה #2

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

דוגמה לשינוי בפריסה שנגרמה על ידי שינוי במיקום של הרכיב

דוגמה 3

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

דוגמה לשינוי בפריסה שנגרמה על ידי שינוי במיקום של הרכיב

דוגמה #4

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

דוגמה שמראה רכיב שמשתנה בגודלו אך לא גורם לשינוי בפריסה

בקישור הבא אפשר לראות הדגמה של האופן שבו שינויים ב-DOM מדווחים על ידי Layout Instability API.

DevTools

חלונית ביצועים

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

צילום מסך של שינוי הפריסה שמוצג בחלונית DevTools Network

כדי לראות מידע נוסף על השינוי בפריסה, לוחצים על שינוי הפריסה ופותחים את חלונית ההזזה Summary. שינויים במאפייני הרכיב מופיעים בפורמט [width, height]. שינויים במיקום של הרכיב מופיעים בפורמט [x,y]. המאפיין הקלט האחרון מציין אם התרחש שינוי בפריסה תוך 500 אלפיות השנייה מהאינטראקציה של המשתמש.

צילום מסך של הכרטיסייה &#39;סיכום&#39; בכלי הפיתוח לגבי שינוי פריסה

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

צילום מסך של הכרטיסייה &#39;יומן אירועים&#39; של כלי הפיתוח לשינוי פריסה

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

הדגשת האזורים שזזים בפריסה

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

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

תהליך מחשבה לזיהוי הגורם לשינויים בפריסה

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

זיהוי הגורם לשינוי פריסה

אלה האירועים שיכולים לגרום לתנודות בפריסה:

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

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

  • האם המיקום או המידות של הרכיב הקודם השתנו?
  • האם רכיב DOM נוסף או הוסר לפני הרכיב שהועבר?
  • האם המיקום של הרכיב שהועבר השתנה באופן מפורש?

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

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

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

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

שינויים במיקום של אלמנט (שאינם כתוצאה מהתנועה של אלמנט אחר)

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

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

שינויים במידות של רכיב

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

  • גיליונות סגנונות שנטענים מאוחר או מחליפים סגנונות שהוצהרו בעבר.
  • תמונות ומסגרות iframe ללא המאפיינים width ו-height שנטענים אחרי עיבוד ה "משבצת" שלהם.
  • בלוקי טקסט ללא המאפיינים width או height שמחלפים גופנים אחרי עיבוד הטקסט.

הוספה או הסרה של רכיבי DOM

בדרך כלל הסיבה לכך היא:

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

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

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

שחזור של שינויי פריסה

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

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

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      debugger;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

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