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

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

Katie Hempenius
Katie Hempenius

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

כלים

Layout Instability API

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

שימוש

אותו קטע קוד מדדים 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 שרלוונטיים ביותר לניפוי באגים של שינויים בפריסה:

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

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, המשמעות היא שהרכיב הועבר מהתצוגה.

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

דוגמה ראשונה

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

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

דוגמה שנייה

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

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

דוגמה 3

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

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

דוגמה 4

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

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

דוגמה לדיווח על שינויים ב-DOM באמצעות Layout Instability API

כלי פיתוח

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

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

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

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

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

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

צילום מסך של הכרטיסייה &#39;יומן אירועים&#39; ב-DevTools לגבי שינוי פריסה

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

בדרך כלל, שינוי כזה נגרם כתוצאה מ:

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

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

בדרך כלל, שינוי כזה נגרם כתוצאה מ:

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

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

פעמים רבות הסיבה לכך היא:

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

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

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

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

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

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