חיפוש ]

שיפור ביצועי Frontend, אנימציות וגלילה באתרים

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

אבל מה לגבי אופטימיזציה לאחר שהעמוד נטען? בעבר לא היו כלים מתאימים בכדי לנתח ביצועים ברמת פרונטאנד (Frontend Performance) והצורך באלו לא היה ברור מאליו.

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

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

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

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

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

על ביצועי Frontend ופעולת ה-Repainting בדפדפנים

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

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

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

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

צינור הרינדור של הדפדפן - הפעלת layout ו-paint

אגב, ישנם מצבים בהם אנו משנים תכונות שאינן גיאומטריות כגון שינוי רקעים (backgrounds), שינוי צבע טקסט, הצללות וכדומה. במצבים אלו אין צורך בביצוע תהליך ה-layout והצינור ייראה בצורה הבאה:

צינור הרינדור של הדפדפן ללא שלב layout

שימוש ב-Chrome Dev Tools לזיהוי צוואר הבקבוק של פעולת ה-Repainting

ניתן להשתמש בכלי המפתחים של כרום (Chrome Developer Tools) על מנת לזהות במהירות אזורים שנצבעים באתר שלכם מחדש. גשו לכלי המפתחים ופתחו את הלשונית Rendering. לאחר מכן הפעילו את האפשרות "Paint flashing" כבתמונה הבאה:

אפשרות Paint Flashing בלשונית Rendering בכלי המפתחים של כרום

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

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

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

שימו לב למספר דברים שרואים בוידאו במהלך הגלילה:

  • חלקו העליון של העמוד (header) נצבע בירוק.
  • כפתורי השיתוף בימין נצבעים בירוק.
  • הבוקסה עם מאמר נוסף (בתחתית העמוד צד שמאל) נצבעת בירוק.

כל החלקים הללו נצבעים מחדש ומעמיסים על הדפדפן בכל פעם שמשתמש מבצע גלילה באתר. יש לכם רעיון מה משותף לשלושתם? אני מניח שניחשתם – לכולם התכונה position: fixed.

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

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

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

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

יצירת שכבות (layers) חדשות עבור אותם אלמנטים

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

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

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

Layer Promotion - הפרדת אלמנטים לשכבות נפרדות בדפדפן

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

התכונה will-change

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

תכונה זו נתמכת בכל הדפדפנים המודרניים וסווגה כ-"Baseline Widely Available" מאז 2022. כאשר תיתנו לתכונה זו את הערך transform, תיווצר שכבה חדשה עבור אותו אלמנט.

.moving-element {
  will-change: transform;
}

שימו לב ש-will-change עם ערכים מסוימים (כגון opacity או transform) יוצרת stacking context חדש, מה שעלול להשפיע על אופן החפיפה של אלמנטים. אם z-index מתנהג בצורה שונה לאחר הוספת will-change, זו כנראה הסיבה.

לדפדפנים ישנים יותר שאינם תומכים ב-will-change, ניתן להשתמש בסוג של hack שקיים כבר שנים – הטריק של translateZ(0):

.moving-element {
  transform: translateZ(0);
}

אך שימו לב למספר נקודות בהקשר לתכונה will-change לפני שאתם רצים להשתמש בה:

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

בואו נראה את התוצאה בסאבי בלוג לאחר שהשתמשתי בתכונה will-change עבור אותם אלמנטים בעייתיים שהזכרנו:

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

כיצד להוסיף את התכונה will-change באמצעות JavaScript?

לצורך המאמר הוספתי את התכונה will-change באמצעות CSS בסאבי בלוג. אך כפי שציינתי, עדיף להשתמש בתכונה זו באמצעות JavaScript בדיוק לפני שהשינוי מתבצע ולהסירה לאחר השינוי.

הנה דוגמה המתארת כיצד לבצע זאת עבור אלמנט מסוים:

var el = document.getElementById('element');

// Set will-change when the element is hovered
el.addEventListener('mouseenter', hintBrowser);
el.addEventListener('animationEnd', removeHint);

function hintBrowser() {
  // The optimizable properties that are going to change
  // in the animation's keyframes block
  this.style.willChange = 'transform, opacity';
}

function removeHint() {
  this.style.willChange = 'auto';
}

התכונה content-visibility

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

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

.below-the-fold-section {
  content-visibility: auto;
  contain-intrinsic-size: auto 500px;
}

התכונה contain-intrinsic-size מספקת לדפדפן גודל משוער לאלמנט, כך שחישובי פס הגלילה יישארו מדויקים גם לפני שהתוכן מרונדר. נכון ל-2025, content-visibility נתמכת ב-Chrome, Edge, Firefox (מגרסה 125+) ו-Safari (מגרסה 18+).

טיפים לביצועי Frontend טובים יותר

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

  • הימנעו משימוש בתמונות רקע להם התכונה background-attachment: fixed. בדפדפנים מסוימים אלו יגרמו לצביעה מחדש במהלך גלילה ולביצועים ירודים.
  • אם אתם משתמשים בסליידרים או אנימציות באתר שלכם, וודאו שאתם יוצרים עבורם שכבה נפרדת באמצעות התכונה will-change.
  • אם ישנם אפקטים רבים של CSS – לדוגמה הרבה פינות מעוגלות (rounded corners), תכונות כמו linear-gradient והצללות (shadows) – שקלו להפחית את השימוש בהן. אין בעיה להשתמש באלו, אך זכרו שבמידה וקיימים במידה מופרזת באתר שלכם, תהיה לכך השפעה על ביצועי ה-Frontend.
  • תמיד השתמשו בגודל התמונה המדויק שעל הדפדפן להציג. אם אתם עובדים עם וורדפרס, תנו מבט במדריך שכתבתי המסביר על יצירת גדלים של תמונות באתרים אלו.
  • לאנימציות מבוססות JavaScript, השתמשו ב-requestAnimationFrame לסנכרון עם מחזור הרענון של הדפדפן. זה מבטיח שקוד האנימציה ירוץ בזמן האופטימלי וימנע ירידת פריימים מיותרת.
  • הקפידו לבצע אנימציה רק על התכונות transform ו-opacity ככל האפשר. אלו התכונות היחידות שניתן לטפל בהן על ידי ה-compositor thread של הדפדפן ללא הפעלת layout או paint. אנימציה של תכונות כמו width, height, top או left יקרה משמעותית יותר.

שאלות נפוצות

שאלות נפוצות בנושא ביצועי Frontend ואופטימיזציית גלילה:

מה גורם לגלילה קופצנית באתרים?
גלילה קופצנית נגרמת בדרך כלל מצביעה מחדש (repainting) כבדה. אלמנטים עם position: fixed, אפקטי CSS מורכבים, תמונות רקע גדולות עם background-attachment: fixed, וטיפולי גלילה כבדים ב-JavaScript יכולים כולם לגרום ל-repaints יקרים שמורידים את קצב הפריימים מתחת ל-60fps.
מהו layer promotion ומתי כדאי להשתמש בו?
Layer promotion משמעו העברת אלמנט לשכבת compositor משלו כך שהוא יכול להיצבע ולבצע אנימציה באופן עצמאי משאר העמוד. השתמשו בו כאשר אלמנט position: fixed או אלמנט שמבצע אנימציה בתדירות גבוהה גורם ל-repaints גלויים. הדרך הפשוטה ביותר היא להחיל will-change: transform על אותו אלמנט.
האם ניתן להוסיף will-change לכל אלמנט בעמוד?
לא. הוספת will-change ליותר מדי אלמנטים היא קונטרפרודוקטיבית. כל שכבה מקודמת צורכת זיכרון GPU, והתקורה של ניהול שכבות רבות עלולה בפועל להחמיר את הביצועים. החילו אותה רק על אלמנטים שגורמים לבעיות ביצועים מדידות.
מה ההבדל בין will-change: transform לבין transform: translateZ(0)?
שתיהן מקדמות אלמנט לשכבה משלו. transform: translateZ(0) הוא hack ישן שמכריח הקשר של transform תלת-ממדי. will-change: transform היא הגישה הסטנדרטית שמסמנת כוונה לדפדפן ללא החלת transform בפועל. השתמשו ב-will-change בדפדפנים מודרניים וב-translateZ(0) כגיבוי רק אם אתם צריכים לתמוך בדפדפנים ישנים מאוד.
אילו תכונות CSS הכי זולות לאנימציה?
התכונות הזולות ביותר לאנימציה הן transform ו-opacity. אלו יכולות להיות מעובדות ב-GPU ללא הפעלת layout או paint. אנימציה של כל תכונה אחרת - כגון width, height, top, left או margin - מפעילה חישובי layout מחדש, שהם יקרים משמעותית.
כיצד content-visibility: auto עוזרת לביצועים?
התכונה content-visibility: auto אומרת לדפדפן לדלג על רינדור (layout ו-paint) עבור אלמנטים שמחוץ למסך. זה יכול להפחית באופן דרמטי את עלות הרינדור הראשונית של עמודים ארוכים. הדפדפן ירנדר את אותם חלקים רק כאשר המשתמש יגלול אליהם.

לסיכום

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

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

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

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

דיון ותגובות
4 תגובות  ]

השאירו תגובה

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

Savvy WordPress Development official logo