למה חלק מהאנימציות איטיות?

בדפדפנים מודרניים אפשר להנפיש שני מאפייני CSS בעלות נמוכה: transform ו-opacity. אם תנפישו משהו אחר, סביר להניח שלא תגיעו ל-60 פריימים לשנייה (FPS) חלקים. בפוסט הזה מוסבר למה זה קורה.

ביצועי האנימציה וקצב הפריימים

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

צינור העיבוד

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

  1. סגנון: חישוב הסגנונות שחלים על הרכיבים.
  2. פריסה: יצירת הגיאומטריה והמיקום של כל רכיב.
  3. צביעה: מילוי הפיקסלים של כל רכיב.
  4. Composite: הפרדת האלמנטים לשכבות וציור השכבות במסך.

ארבעת השלבים האלה נקראים צינור העיבוד של הדפדפן.

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

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

הנפשת מאפייני פריסה

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

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

הנפשת מאפייני צבע

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

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

הנפשה של מאפיינים מורכבים

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

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

מהי שכבה?

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

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

ביצועים של CSS לעומת JavaScript

יכול להיות שתשאלו את עצמכם: מבחינת ביצועים, עדיף להשתמש ב-CSS או ב-JavaScript לאנימציות?

אנימציות מבוססות CSS ו-Web Animations (בדפדפנים שתומכים ב-API) מטופלות בדרך כלל בשרשור שנקרא compositor thread. הוא שונה מהשרשור הראשי של הדפדפן, שבו מבוצעים עיצוב, פריסה, ציור ו-JavaScript. כלומר, אם הדפדפן מריץ משימות כבדות בשרשור הראשי, האנימציות האלה יכולות להמשיך לפעול בלי הפרעה.

כמו שמוסבר במאמר הזה, במקרים רבים אפשר לטפל בשינויים אחרים בטרנספורמציות ובאטימות באמצעות ה-compositor thread.

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