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

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

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

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

תמיכת דפדפן

תמיכה בדפדפן

  • 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 כאומדן של הגובה והרוחב של הקטעים.

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

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

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

סיכום

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