ניראות (content-visiability): נכס ה-CSS החדש שמשפר את ביצועי הרינדור

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

המאפיין content-visibility, שמושק ב-Chromium 85, עשוי להיות אחד ממאפייני ה-CSS החדשים בעלי ההשפעה הרבה ביותר, לשיפור הביצועים של טעינת הדפים. content-visibility מאפשר לסוכן המשתמש לדלג על עבודת הרינדור של האלמנט, כולל פריסה וצביעה, עד שיהיה צורך בכך. מכיוון שיש דילוג על הרינדור, אם חלק גדול מהתוכן שלכם לא מופיע במסך, השימוש במאפיין content-visibility גורם למשתמש הראשוני להיטען מהר יותר. כך גם מאפשר אינטראקציה מהירה יותר עם התוכן שמופיע במסך. יפה.

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

תמיכת דפדפן

תמיכה בדפדפן

  • 85
  • 85
  • 124

מקור

content-visibility מסתמך על אלמנטים בסיסיים במפרט שירותי ה-CSS. נכון לעכשיו content-visibility נתמך רק ב-Chromium 85 (ונקרא 'יצירת אב טיפוס' ל-Firefox), אבל מפרט ה-containment נתמך בדפדפנים המודרניים ביותר.

עצירת תשלום של שירות CSS

היעד הכללי והמטרה הכוללת של עצירת ה-CSS היא לאפשר שיפורי ביצועי רינדור של תוכן מהאינטרנט, על ידי מתן בידוד צפוי של תת-עץ DOM משאר הדף.

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

יש ארבעה סוגים של מאגרי CSS – כל אחד מהם יכול להיות ערך פוטנציאלי למאפיין ה-CSS contain, שאפשר לשלב ברשימת ערכים המופרדים ברווחים:

  • size: הפרדה בגודל של אלמנט מבטיחה שניתן יהיה לפרוס את התיבה של הרכיב בלי לבדוק את הצאצאים שלו. כלומר, אנחנו יכולים לדלג על פריסת הצאצאים אם כל מה שאנחנו צריכים הוא את גודל הרכיב.
  • layout: בלימת הפריסה המשמעות היא שצאצאים לא משפיעים על הפריסה החיצונית של תיבות אחרות בדף. כך אנחנו יכולים לדלג על הפריסה של הצאצאים אם כל מה שאנחנו רוצים לעשות הוא לפרוס תיבות אחרות.
  • style: החרגת סגנונות מבטיחה שמאפיינים שיכולים להשפיע על פריטים נוספים מלבד הצאצאים שלו לא יסמנו בתו בריחה את הרכיב (למשל מונה). כך אנחנו יכולים לדלג על חישוב סגנון עבור הצאצאים אם כל מה שאנחנו רוצים הוא לחשב סגנונות באלמנטים אחרים.
  • paint: בידוד צבע מבטיח שהצאצאים של התיבה שמכילה את התיבה לא יוצגו מחוץ לגבולות שלה. שום דבר לא יכול לחרוג באופן גלוי מהאלמנט. אם רכיב מסוים נמצא מחוץ למסך או לא גלוי מסיבה אחרת, גם הצאצאים שלו לא יהיו גלויים. כך אנחנו יכולים לדלג על הצגת הצאצאים אם הרכיב לא נמצא במסך.

מדלג על עבודה הרינדור עם content-visibility

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

המאפיין של הרשאות הגישה לתוכן מקבל כמה ערכים, אבל auto הוא הערך שמאפשר שיפור מיידי בביצועים. רכיב עם content-visibility: auto מקבל מכסה של layout, style ו-paint. אם האלמנט נמצא מחוץ למסך (ולא רלוונטי למשתמש בדרכים אחרות), הרכיבים הרלוונטיים הם אלה שבהם יש מיקוד או בחירה בעץ המשנה), הוא מקבל גם בלימת size (ומפסיקים לצבוע ולבדוק את התוכן).

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

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

הערה בנושא נגישות

אחת התכונות של content-visibility: auto היא שהתוכן שלא מוצג במסך נשאר זמין במודל האובייקט של המסמך, ולכן גם בעץ הנגישות (בניגוד ל-visibility: hidden). כלומר, אפשר לחפש את התוכן הזה בדף ולנווט אליו, בלי להמתין לטעינתו או לפגוע בביצועי העיבוד.

עם זאת, הצד ההפוך הוא שרכיבי ציון דרך עם תכונות סגנון כמו display: none או visibility: hidden יופיעו גם בעץ הנגישות כשהם מחוץ למסך, כי הדפדפן לא יציג את הסגנונות האלה עד שהם ייכנסו לאזור התצוגה. כדי שהן לא יופיעו בעץ הנגישות, וזה עלול לגרום לבלגן, מומלץ להוסיף גם את aria-hidden="true".

לדוגמה: בלוג בנושא טיולים

בדוגמה הזו, אנחנו מתבססים על בלוג הטיולים שלנו בצד שמאל, ומחילים את content-visibility: auto על אזורים במקטעים בצד שמאל. התוצאות מציגות זמני רינדור, שנעים בין 232 אלפיות השנייה ל-30 אלפיות שנייה בטעינה הראשונית של הדף.

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

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

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

צילום מסך של בלוג בנושא טיולים.
דוגמה לבלוג בנושא טיולים. ראו הדגמה על Codepen

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

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

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

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

צילום מסך עם הערות של קיבוץ התוכן לקטעים באמצעות מחלקה של CSS.
דוגמה לקיבוץ תוכן בקטעים שבהם הוחלה המחלקה story, כדי לקבל content-visibility: auto. ראו הדגמה על Codepen

לאחר מכן מחילים את כלל הסגנון הבא על הקטעים:

.story {
  content-visibility: auto;
  contain-intrinsic-size: 1000px; /* Explained in the next section. */
}

ציון הגודל הטבעי של רכיב באמצעות contain-intrinsic-size

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

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

למרבה המזל, CSS מספק מאפיין נוסף, contain-intrinsic-size, שמציין למעשה את הגודל הטבעי של הרכיב אם הרכיב מושפע על ידי הגבלת גודל. בדוגמה שלנו נקבע אותו כ-1000px כאומדן לגובה ולרוחב של הקטעים.

כלומר, הפריסה תתפרס כאילו היה לו צאצא יחיד של 'גודל פנימי', מה שמבטיח שה-divs הלא בגודלם עדיין תופסים מקום. contain-intrinsic-size משמש כגודל placeholder במקום תוכן שעבר רינדור.

ב-Chromium בגרסה 98 ואילך, יש מילת מפתח חדשה מסוג auto ל-contain-intrinsic-size. אם צוין, הדפדפן יזכור את הגודל האחרון שעבר עיבוד, אם יש כזה, וישתמש בו במקום בגודל ה-placeholder שסופק על ידי המפתח. לדוגמה, אם ציינתם את הערך contain-intrinsic-size: auto 300px, הגודל הפנימי של הרכיב יתחיל להיות 300px בכל מימד, אבל אחרי עיבוד התוכן של הרכיב הוא יישמר בגודל הפנימי שעבר רינדור. כל שינוי נוסף בגודל העיבוד יישמר גם הוא. בפועל, המשמעות היא שאם גוללים ברכיב עם content-visibility: auto ואז גוללים חזרה אל מחוץ למסך, הרוחב והגובה האידאליים יישמרו באופן אוטומטי, ולא ישתנו הגודל של ה-placeholder. התכונה הזו שימושית במיוחד בגוללים אינסופיים, שעכשיו יכולים לשפר באופן אוטומטי את הערכת הגודל לאורך זמן בזמן שהמשתמש מעיין בדף.

מסתיר תוכן באמצעות content-visibility: hidden

מה קורה אם רוצים שהתוכן לא יעבור עיבוד גם אם לא יופיע על המסך וגם אם לא, ולמנף את היתרונות של מצב העיבוד במטמון? מזינים: content-visibility: hidden.

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

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

ניתן להשוות זאת לדרכים נפוצות אחרות להסתרת תוכן של אלמנטים:

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

לעומת זאת, content-visibility: hidden מסתיר את הרכיב תוך שמירה על מצב הרינדור שלו, כך שאם יש שינויים שצריך להתרחש, הם קורים רק כשהרכיב מוצג שוב (כלומר, אם מסירים את המאפיין content-visibility: hidden).

חלק מהתרחישים לדוגמה השימושיים ב-content-visibility: hidden הם כשמטמיעים גלילות וירטואליות מתקדמות ומודדים את הפריסה. הן מעולה גם לאפליקציות עם דף יחיד (SPA). אפשר להשאיר תצוגות של אפליקציות לא פעילות ב-DOM כשמחילים את content-visibility: hidden כדי למנוע את התצוגה שלהן אבל לשמור על המצב שלהן במטמון. כך התצוגה תעבור עיבוד מהיר כאשר היא תחזור להיות פעילה.

ההשפעות על אינטראקציה עד הצבע הבא (INP)

INP הוא מדד שמעריך את היכולת של דף להגיב באופן מהימן לקלט של משתמשים. רמת התגובה יכולה להיות מושפעת מעבודה רבה מדי על ה-thread הראשי, כולל עבודות רינדור.

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

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

סיכום

המשמעות של content-visibility ומפרט ה-CSS Containment (מפרט) של CSS היא שיפורי ביצועים מעולים ישירות בקובץ ה-CSS. למידע נוסף על המאפיינים האלה, כדאי לעיין במאמרים הבאים: