לגודל DOM גדול יש השפעה גדולה יותר על האינטראקטיביות ממה שאפשר לחשוב. במדריך הזה נסביר למה זה קורה ומה אפשר לעשות.
אין דרך לעקוף את זה: כשיוצרים דף אינטרנט, לדף הזה יהיה Document Object Model (DOM). מודל ה-DOM מייצג את המבנה של קוד ה-HTML בדף, ומעניק ל-JavaScript ול-CSS גישה למבנה ולתוכן של הדף.
הבעיה היא שהגודל של ה-DOM משפיע על היכולת של הדפדפן לבצע רינדור של דף במהירות וביעילות. באופן כללי, ככל ש-DOM גדול יותר, כך הרינדור הראשוני של הדף יקר יותר, וגם העדכון של הרינדור בשלב מאוחר יותר במחזור החיים של הדף.
הבעיה הזו מתרחשת בדפים עם DOM גדול מאוד, כשאינטראקציות שמשנות או מעדכנות את ה-DOM מפעילות עבודת פריסה יקרה שמשפיעה על היכולת של הדף להגיב במהירות. עבודת פריסה יקרה יכולה להשפיע על מהירות התגובה לאינטראקציה באתר (INP). אם רוצים שהדף יגיב במהירות לאינטראקציות של משתמשים, חשוב לוודא שגודלי ה-DOM יהיו רק גדולים ככל שצריך.
מתי ה-DOM של דף גדול מדי?
לפי Lighthouse, גודל ה-DOM של דף הוא גדול מדי אם הוא חורג מ-1,400 צמתים. Lighthouse יתחיל להציג אזהרות כשמספר הצמתים ב-DOM של דף מסוים יעלה על 800. לדוגמה, קוד ה-HTML הבא:
<ul>
<li>List item one.</li>
<li>List item two.</li>
<li>List item three.</li>
</ul>
בדוגמת הקוד שלמעלה יש ארבעה רכיבי DOM: הרכיב <ul>
ושלושת רכיבי הצאצא <li>
שלו. כמעט בטוח שיהיו בדף האינטרנט שלכם הרבה יותר צמתים מאשר בדוגמה הזו, ולכן חשוב להבין מה אפשר לעשות כדי לשלוט בגודל של ה-DOM, וגם להכיר אסטרטגיות אחרות לאופטימיזציה של עבודת הרינדור אחרי שמקטינים את ה-DOM של הדף ככל האפשר.
איך נפחי DOM גדולים משפיעים על ביצועי הדף?
נפחי DOM גדולים משפיעים על ביצועי הדף בכמה דרכים:
- במהלך העיבוד הראשוני של הדף. כשמחילים CSS על דף, נוצר מבנה שדומה ל-DOM, שנקרא מודל אובייקט CSS (CSSOM). ככל שהספציפיות של סלקטורי ה-CSS גדלה, ה-CSSOM הופך למורכב יותר, ונדרש יותר זמן להפעלת הפעולות הדרושות של פריסת הרכיבים, העיצוב, ההרכבה והציור, שנדרשות כדי לצייר את דף האינטרנט על המסך. העבודה הנוספת הזו מגדילה את זמן האחזור של אינטראקציות שמתרחשות בשלב מוקדם במהלך טעינת הדף.
- כשאינטראקציות משנות את ה-DOM, בין אם על ידי הוספה או מחיקה של רכיבים, או על ידי שינוי התוכן והסגנונות של ה-DOM, העבודה שנדרשת כדי לעבד את העדכון הזה עלולה לגרום לעלויות גבוהות מאוד של פריסה, עיצוב, קומפוזיציה וציור. כמו במקרה של הרינדור הראשוני של הדף, עלייה בספציפיות של סלקטור CSS יכולה להוסיף לעבודת הרינדור כשאלמנטים של HTML מוכנסים ל-DOM כתוצאה מאינטראקציה.
- כש-JavaScript מבצע שאילתה ב-DOM, הפניות לרכיבי DOM מאוחסנות בזיכרון. לדוגמה, אם קוראים ל-
document.querySelectorAll
כדי לבחור את כל רכיבי<div>
בדף, עלות הזיכרון יכולה להיות משמעותית אם התוצאה מחזירה מספר גדול של רכיבי DOM.
כל הגורמים האלה יכולים להשפיע על האינטראקטיביות, אבל הפריט השני ברשימה שלמעלה חשוב במיוחד. אם אינטראקציה גורמת לשינוי ב-DOM, היא יכולה להפעיל הרבה עבודה שיכולה לתרום לערך INP נמוך בדף.
איך מודדים את גודל ה-DOM?
יש כמה דרכים למדוד את גודל ה-DOM. השיטה הראשונה משתמשת ב-Lighthouse. כשמריצים ביקורת, הנתונים הסטטיסטיים של ה-DOM בדף הנוכחי מופיעים בביקורת 'Avoid an excessive DOM size' (הימנעות מנפח DOM גדול מדי) בקטע 'אבחון'. בקטע הזה אפשר לראות את המספר הכולל של רכיבי DOM, את רכיב ה-DOM שמכיל הכי הרבה רכיבי צאצא ואת רכיב ה-DOM העמוק ביותר.
שיטה פשוטה יותר היא להשתמש בלוח JavaScript בכלים למפתחים בכל דפדפן מרכזי. כדי לקבל את המספר הכולל של רכיבי HTML ב-DOM, אפשר להשתמש בקוד הבא במסוף אחרי שהדף נטען:
document.querySelectorAll('*').length;
אם רוצים לראות את העדכון של גודל ה-DOM בזמן אמת, אפשר להשתמש גם בכלי לניטור ביצועים. בעזרת הכלי הזה אפשר ליצור קורלציה בין פעולות פריסה וסגנון (והיבטים אחרים של ביצועים) לבין הגודל הנוכחי של DOM.
אם הגודל של ה-DOM מתקרב לסף האזהרה של גודל ה-DOM ב-Lighthouse או חורג ממנו, השלב הבא הוא להבין איך להקטין את הגודל של ה-DOM כדי לשפר את היכולת של הדף להגיב לאינטראקציות של המשתמשים, וכך לשפר את מדד INP של האתר.
איך אפשר למדוד את מספר רכיבי ה-DOM שמושפעים מאינטראקציה?
אם אתם יוצרים פרופיל של אינטראקציה איטית במעבדה ואתם חושדים שהיא קשורה לגודל ה-DOM של הדף, אתם יכולים לבחור כל חלק בפעילות בפרופיל שנקרא 'חישוב מחדש של הסגנון' ולבחון את הנתונים ההקשריים בחלונית התחתונה כדי להבין כמה רכיבי DOM הושפעו.
בצילום המסך שלמעלה אפשר לראות שכשבוחרים את העבודה, החישוב מחדש של הסגנון מציג את מספר האלמנטים שהושפעו. בצילום המסך שלמעלה מוצג מקרה קיצוני של ההשפעה של גודל ה-DOM על עבודת הרינדור בדף עם הרבה רכיבי DOM. עם זאת, המידע האבחוני הזה שימושי בכל מקרה כדי לקבוע אם גודל ה-DOM הוא גורם מגביל במשך הזמן שנדרש לרינדור הפריים הבא בתגובה לאינטראקציה.
איך אפשר להקטין את נפח ה-DOM?
בנוסף לביקורת על קוד ה-HTML של האתר כדי לזהות תגי עיצוב מיותרים, הדרך העיקרית לצמצם את גודל ה-DOM היא לצמצם את עומק ה-DOM. אחד הסימנים לכך שעומק ה-DOM גדול מדי הוא אם אתם רואים תגי עיצוב שדומים לזה בכרטיסייה Elements בכלי הפיתוח של הדפדפן:
<div>
<div>
<div>
<div>
<!-- Contents -->
</div>
</div>
</div>
</div>
כשמזהים דפוסים כאלה, אפשר לפשט אותם על ידי שיטוח מבנה ה-DOM. הפעולה הזו תצמצם את מספר רכיבי ה-DOM, וכנראה תאפשר לכם לפשט את הסגנונות של הדף.
עומק ה-DOM יכול להיות גם סימפטום של המסגרות שבהן אתם משתמשים. בפרט, במסגרות שמבוססות על רכיבים, כמו אלה שמסתמכות על JSX, צריך להטמיע כמה רכיבים בתוך מאגר אב.
עם זאת, הרבה מסגרות מאפשרות להימנע מהוספת רכיבים בתוך רכיבים באמצעות מה שנקרא פרגמנטים. מסגרות מבוססות-רכיבים שמציעות קטעים כתכונה כוללות (אבל לא רק) את האפשרויות הבאות:
באמצעות פרגמנטים בפריימוורק שתבחרו, תוכלו לצמצם את עומק ה-DOM. אם אתם חוששים מההשפעה של שיטוח מבנה ה-DOM על הסגנון, כדאי לכם להשתמש במצבי פריסה מודרניים יותר (ומהירים יותר) כמו flexbox או grid.
שיטות אחרות שכדאי לשקול
גם אם תעשו מאמצים כדי לשטח את עץ ה-DOM ולהסיר רכיבי HTML מיותרים כדי לשמור על DOM קטן ככל האפשר, הוא עדיין יכול להיות גדול למדי ולהפעיל הרבה עבודת רינדור כשהוא משתנה בתגובה לאינטראקציות של המשתמשים. אם אתם נתקלים במצב כזה, יש כמה אסטרטגיות נוספות שתוכלו לשקול כדי להגביל את עבודת הרינדור.
כדאי לשקול גישה מצטברת
יכול להיות שחלקים גדולים מהדף לא יהיו גלויים למשתמש בהתחלה, כשהדף מוצג בפעם הראשונה. אפשר לנצל את ההזדמנות הזו כדי להשתמש בטעינה עצלה של HTML. לשם כך, צריך להשמיט את החלקים האלה של ה-DOM בהפעלה, אבל להוסיף אותם כשהמשתמש מקיים אינטראקציה עם החלקים בדף שדורשים את ההיבטים שמוסתרים בהתחלה בדף.
הגישה הזו שימושית גם במהלך הטעינה הראשונית ואולי גם לאחר מכן. בטעינת הדף הראשונית, יש פחות עבודת עיבוד מראש, כלומר מטען ה-HTML הראשוני יהיה קל יותר והעיבוד יהיה מהיר יותר. כך יהיו לאינטראקציות במהלך התקופה הקריטית הזו יותר הזדמנויות לפעול עם פחות תחרות על תשומת הלב של השרשור הראשי.
אם יש לכם הרבה חלקים בדף שמוסתרים בהתחלה בזמן הטעינה, יכול להיות שזה גם יזרז אינטראקציות אחרות שמפעילות עבודה של עיבוד מחדש. עם זאת, ככל שאינטראקציות אחרות מוסיפות עוד רכיבים ל-DOM, עבודת הרינדור תגדל ככל שה-DOM יגדל במהלך מחזור החיים של הדף.
הוספה ל-DOM לאורך זמן יכולה להיות מסובכת, ויש לה חסרונות משלה. אם אתם בוחרים בדרך הזו, סביר להניח שאתם שולחים בקשות לרשת כדי לקבל נתונים לאכלוס ה-HTML שאתם מתכוונים להוסיף לדף בתגובה לאינטראקציה של משתמש. בקשות רשת שנמצאות בתהליך לא נספרות ב-INP, אבל הן יכולות להגדיל את זמן האחזור הנתפס. אם אפשר, כדאי להציג סמל טעינה או אינדיקטור אחר שמציין שהנתונים נשלפים, כדי שהמשתמשים יבינו שמשהו קורה.
הגבלת המורכבות של סלקטורים ב-CSS
כשדפדפן מנתח סלקטורים ב-CSS, הוא צריך לעבור על עץ ה-DOM כדי להבין איך – ואם – הסלקטורים האלה חלים על הפריסה הנוכחית. ככל שהסלקטורים האלה מורכבים יותר, כך הדפדפן צריך לעבוד יותר כדי לבצע את הרינדור הראשוני של הדף, וגם כדי לבצע חישובים מחדש של הסגנון ועבודת פריסה אם הדף משתנה כתוצאה מאינטראקציה.
שימוש במאפיין content-visibility
ב-CSS יש מאפיין content-visibility
, שמאפשר למעשה לבצע טעינה עצלה של רכיבי DOM שלא מוצגים במסך. כשהרכיבים מתקרבים לאזור התצוגה, הם מוצגים לפי דרישה. היתרונות של content-visibility
לא מסתכמים רק בקיצוץ משמעותי של עבודת הרינדור ברינדור הראשוני של הדף, אלא גם בדילוג על עבודת הרינדור של רכיבים מחוץ למסך כש-DOM של הדף משתנה כתוצאה מאינטראקציה של משתמש.
סיכום
צמצום גודל ה-DOM רק למה שבאמת נחוץ הוא דרך טובה לבצע אופטימיזציה של ה-INP באתר. כך אפשר לצמצם את הזמן שנדרש לדפדפן לבצע עבודת פריסה ורינדור כשמתבצע עדכון של ה-DOM. גם אם אי אפשר לצמצם את גודל ה-DOM באופן משמעותי, יש כמה טכניקות שאפשר להשתמש בהן כדי לבודד את עבודת הרינדור לעץ משנה של ה-DOM, כמו CSS containment ומאפיין ה-CSS content-visibility
.
בכל מקרה, אם תצליחו ליצור סביבה שבה עבודת הרינדור מצומצמת, וגם לצמצם את כמות עבודת הרינדור שהדף מבצע בתגובה לאינטראקציות, התוצאה תהיה שהמשתמשים ירגישו שהאתר שלכם מגיב מהר יותר לאינטראקציות שלהם. המשמעות היא שערך ה-INP של האתר יהיה נמוך יותר, וזה ישפר את חוויית המשתמש.