הימנעות מצבעים מיותרים

מבוא

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

ציור: סיור מהיר במיוחד

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

תהליך הציור עצמו מעניין. ב-Chrome, שילוב של עץ של DOM ו-CSS עובר רסטר על ידי תוכנה שנקראת Skia. אם פעם שיחקתם פעם עם רכיב ה-canvas של Skia, ה-API של Skia לא ייראה לכם מוכר. יש הרבה פונקציות בסגנון moveTo ו-lineTo וגם כמה פונקציות מתקדמות יותר. למעשה כל האלמנטים שצריך לצבוע מזקקים לאוסף של קריאות Skia שניתן להוציא לפועל, והפלט של הוא קבוצה של מפות ביטים. מפות הסיביות האלה מועלות ל-GPU, וה-GPU עוזר ליצור אותן יחד כדי לספק לנו את התמונה הסופית על המסך.

מעבר בין פיקסלים בפיקסלים

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

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

גלילה

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

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

הצגת מלבני צבע בכלי הפיתוח ל-Chrome
הצגת מלבני צבע בכלים למפתחים ב-Chrome

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

בעבר כתבתי מאמר על ביצועי גלילה. מומלץ לקרוא את המאמר הזה אם אתם רוצים לקבל מידע נוסף על ביצועי הגלילה.

אינטראקציות

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

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

שילוב מצער

הדגמה עם צבעים יקרים
הדגמה עם צבעים יקרים

מה קורה אם אני גולל ומזיז את העכבר בו-זמנית? זה בהחלט אפשרי עבורי "ליצור אינטראקציה" בטעות עם רכיב כאשר אני גולל לאורכו, וכתוצאה מכך נוצר צבע יקר. השינוי הזה יכול להקפיץ אותי במגבלת תקציב הפריימים של כ-16.7 אלפיות השנייה (משך הזמן הדרוש לנו כדי להישאר בקצב של 60 פריימים לשנייה). יצרתי הדגמה כדי להראות לך בדיוק למה אני מתכוון. אני מקווה שתוך כדי גלילה ותזיז את העכבר תראו את האפקטים של העברת העכבר, אבל בואו נראה איך כלי הפיתוח של Chrome עושים את זה:

כלי הפיתוח של Chrome שמציגים פריימים יקרים
כלי הפיתוח של Chrome שמציגים פריימים יקרים

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

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

הנה הקוד:

// Used to track the enabling of hover effects
var enableTimer = 0;

/*
 * Listen for a scroll and use that to remove
 * the possibility of hover effects
 */
window.addEventListener('scroll', function() {
  clearTimeout(enableTimer);
  removeHoverClass();

  // enable after 1 second, choose your own value here!
  enableTimer = setTimeout(addHoverClass, 1000);
}, false);

/**
 * Removes the hover class from the body. Hover styles
 * are reliant on this class being present
 */
function removeHoverClass() {
  document.body.classList.remove('hover');
}

/**
 * Adds the hover class to the body. Hover styles
 * are reliant on this class being present
 */
function addHoverClass() {
  document.body.classList.add('hover');
}

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

/* Expect the hover class to be on the body
 before doing any hover effects */
.hover .block:hover {
 …
}

וזה כל הסיפור!

סיכום

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

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

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