דמיינו את זה: אתם מצטרפים לפרויקט חדש, צוללים לתוך בסיס הקוד, ותוך השעות הראשונות, אתם מגלים משהו מוכר בצורה מתסכלת. מפוזרים בכל גיליונות הסגנונות, אתה מוצא מספר הגדרות @keyframes עבור אותן אנימציות בסיסיות. שלושה אפקטים שונים של דהייה, שתיים או שלוש וריאציות שקופיות, קומץ אנימציות זום ולפחות שתי אנימציות ספין שונות כי, ובכן, למה לא? @keyframes דופק { מאת { קנה מידה: 1; } אל { קנה מידה: 1.1; } }
@keyframes bigger-pulse { 0%, 20%, 100% { קנה מידה: 1; } 10%, 40% { קנה מידה: 1.2; } }
אם התרחיש הזה נשמע מוכר, אתה לא לבד. מניסיוני על פני פרויקטים שונים, אחד הניצחונות המהירים העקביים ביותר שאני יכול לספק הוא איחוד וסטנדרטיזציה של מסגרות מפתח. זה הפך לדפוס אמין כל כך, שאני מצפה כעת לניקוי זה כאחת המשימות הראשונות שלי בכל בסיס קוד חדש. ההיגיון מאחורי הכאוס היתירות הזו הגיונית לחלוטין כשחושבים על זה. כולנו משתמשים באותן אנימציות בסיסיות בעבודה היומיומית שלנו: דהייה, שקופיות, זומים, ספינים ואפקטים נפוצים אחרים. האנימציות האלה הן די פשוטות, וקל ליצור הגדרה מהירה של @keyframes כדי לבצע את העבודה. ללא מערכת אנימציה מרכזית, מפתחים כותבים באופן טבעי את הפריימים המפתח הללו מאפס, מבלי לדעת שהנפשות דומות כבר קיימות במקומות אחרים בבסיס הקוד. זה נפוץ במיוחד כאשר עובדים בארכיטקטורות מבוססות רכיבים (מה שרובנו עושים בימינו), מכיוון שצוותים עובדים לרוב במקביל על פני חלקים שונים של האפליקציה. התוצאה? כאוס אנימציה. הבעיה הקטנה הבעיות הברורות ביותר בשכפול של מסגרות מפתח הן זמן פיתוח מבוזבז ונפיחות קוד מיותרת. הגדרות מרובות של פריים מפתח אומרות מספר מקומות לעדכון כאשר הדרישות משתנות. צריך להתאים את התזמון של אנימציית הדעיכה שלך? תצטרך לחפש כל מופע בבסיס הקוד שלך. רוצה לעשות סטנדרטיזציה של פונקציות ההקלה? בהצלחה במציאת כל הווריאציות. ריבוי נקודות תחזוקה זה הופך אפילו עדכוני אנימציה פשוטים למשימה שגוזלת זמן. הבעיה הגדולה יותר שכפול מסגרות מפתח זה יוצר בעיה ערמומית הרבה יותר האורבת מתחת לפני השטח: מלכודת ההיקף הגלובלית. גם כאשר עובדים עם ארכיטקטורות מבוססות רכיבים, מסגרות מפתח של CSS תמיד מוגדרות בהיקף הגלובלי. המשמעות היא שכל פריימים המפתח חלים על כל הרכיבים. תָמִיד. כן, האנימציה שלך לא בהכרח משתמשת במסגרות המפתח שהגדרת ברכיב שלך. הוא משתמש במסגרות המפתח האחרונות שתואמות לאותו שם בדיוק שנטענו להיקף הגלובלי. כל עוד כל מסגרות המפתח שלך זהות, זו עשויה להיראות כמו בעיה קלה. אבל ברגע שאתה רוצה להתאים אישית אנימציה למקרה שימוש ספציפי, אתה בצרות, או גרוע מכך, אתה תהיה זה שגורם להם. או שהאנימציה שלך לא תעבוד בגלל שרכיב אחר שנטען אחרי שלך, מחליף את ה-keyframes שלך, או שהרכיב שלך נטען אחרון ומשנה בטעות את התנהגות האנימציה של כל רכיב אחר המשתמש בשם של keyframe זה, ואולי אפילו לא תבין זאת. הנה דוגמה פשוטה שמדגימה את הבעיה: .component-one { /* סגנונות רכיבים */ אנימציה: דופק 1s קלות-in-out חלופי אינסופי; }
/* הגדרת @keyframes זו לא תעבוד */ @keyframes דופק { מאת { קנה מידה: 1; } אל { קנה מידה: 1.1; } }
/* בהמשך הקוד... */
.component-two { /* סגנונות רכיבים */ אנימציה: pulse 1s קלות-in-out אינסופי; }
/* מסגרות מפתח זה יחול על שני הרכיבים */ @keyframes דופק { 0%, 20%, 100% { קנה מידה: 1; } 10%, 40% { קנה מידה: 1.2; } }
שני הרכיבים משתמשים באותו שם אנימציה, אבל ההגדרה @keyframes השנייה מחליפה את הראשונה. כעת גם רכיב אחד וגם רכיב שני ישתמשו במסגרות המפתח השניות, ללא קשר לאיזה רכיב הגדיר אילו פריימים. ראה את אסימוני ה-Pen Keyframes - הדגמה 1 [מזלג] מאת עמית שין. החלק הכי גרוע? לעתים קרובות זה עובד בצורה מושלמת בפיתוח מקומי אך נשבר באופן מסתורי בייצור כאשר תהליכי בנייה משנים את סדר הטעינה של גיליונות הסגנונות שלך. בסופו של דבר אתה מקבל אנימציות שמתנהגות אחרת תלוי אילו רכיבים נטענים ובאיזה רצף. הפתרון: מסגרות מפתח מאוחדות התשובה לכאוס הזה היא פשוטה להפליא: מסגרות מפתח דינמיות מוגדרות מראש המאוחסנות בגיליון סגנונות משותף. במקום לאפשר לכל רכיב להגדיר אנימציות משלו, אנו יוצרים פריימים מרכזיים מתועדים היטב, קלים לביצועלשימוש, לתחזוקה ומותאם לצרכים הספציפיים של הפרויקט שלך. תחשוב על זה בתור אסימוני מפתחות. בדיוק כפי שאנו משתמשים באסימונים עבור צבעים ומרווחים, ורבים מאיתנו כבר משתמשים באסימונים עבור מאפייני הנפשה, כמו פונקציות משך והקלה, מדוע לא להשתמש באסימונים גם עבור פריים מפתח? גישה זו יכולה להשתלב באופן טבעי עם כל זרימת עבודה נוכחית של אסימון עיצוב שבו אתה משתמש, תוך פתרון הן את הבעיה הקטנה (שכפול קוד) והן את הבעיה הגדולה יותר (התנגשויות בהיקף גלובלי) במכה אחת. הרעיון הוא פשוט: צור מקור אחד של אמת לכל האנימציות הנפוצות שלנו. גיליון סגנונות משותף זה מכיל מסגרות מפתח מעוצבות בקפידה המכסים את דפוסי האנימציה שהפרויקט שלנו משתמש בו בפועל. לא עוד לנחש אם אנימציית דהייה כבר קיימת איפשהו בבסיס הקוד שלנו. לא עוד דרוס בטעות אנימציות מרכיבים אחרים. אבל הנה המפתח: אלו אינן רק אנימציות העתק-הדבק סטטיות. הם נועדו להיות דינמיים וניתנים להתאמה אישית באמצעות מאפיינים מותאמים אישית של CSS, מה שמאפשר לנו לשמור על עקביות תוך כדי גמישות להתאים אנימציות למקרי שימוש ספציפיים, כמו אם אתה צריך אנימציית "פולס" קצת יותר גדולה במקום אחד. בניית אסימון Keyframes הראשון אחד מהפירות הנמוכים הראשונים שעלינו להתמודד הוא האנימציה "דהיוך". באחד הפרויקטים האחרונים שלי, מצאתי למעלה מתריסר הגדרות דהייה נפרדות, וכן, כולן פשוט הנפשו את האטימות מ-0 ל-1. אז בואו ניצור גיליון סגנונות חדש, נקרא לו kf-tokens.css, לייבא אותו לפרויקט שלנו, ונמקם את ה-keyframes שלנו עם הערות מתאימות בתוכו. /* keyframes-tokens.css */
/* * Fade In - אנימציית כניסה לדעוך * שימוש: אנימציה: קפ-דעוך-אין 0.3s קלות-אאוט; */ @keyframes kf-fade-in { מאת { אטימות: 0; } אל { אטימות: 1; } }
הצהרת @keyframes הבודדת הזו מחליפה את כל הנפשות הדה-אין המפוזרות על פני בסיס הקוד שלנו. נקי, פשוט וישים ברחבי העולם. ועכשיו, לאחר שהוגדר לנו האסימון הזה, אנחנו יכולים להשתמש בו מכל רכיב במהלך הפרויקט שלנו: .modal { אנימציה: קפ-דעוך-אין 0.3s ease-out; }
.tooltip { אנימציה: kf-fade-in 0.2s ease-in-out; }
.notification { אנימציה: kf-fade-in 0.5s ease-out; }
ראה את אסימוני ה-Pen Keyframes - הדגמה 2 [מזלג] מאת עמית שין. הערה: אנו משתמשים בקידומת kf- בכל שמות ה-@keyframes שלנו. קידומת זו משמשת כמרחב שמות שמונע התנגשויות שמות עם אנימציות קיימות בפרויקט ומבהירה מיד שהפריימים המפתח הללו מגיעים מקובץ אסימוני הפריימים שלנו. יצירת שקופית דינמית ה-kf-fade-in keyframes עובדים מצוין כי זה פשוט ויש מעט מקום לבלבל דברים. באנימציות אחרות, לעומת זאת, אנחנו צריכים להיות הרבה יותר דינמיים, וכאן נוכל למנף את הכוח העצום של מאפייני CSS מותאמים אישית. זה המקום שבו אסימוני keyframes באמת זוהרים בהשוואה להנפשות סטטיות מפוזרות. בואו ניקח תרחיש נפוץ: אנימציות "מחליקות". אבל להחליק מאיפה? 100 פיקסלים מימין? 50% משמאל? האם זה צריך להיכנס מהחלק העליון של המסך? או אולי לצוף מלמטה? כל כך הרבה אפשרויות, אבל במקום ליצור מסגרות מפתח נפרדות לכל כיוון ולכל וריאציה, אנחנו יכולים לבנות אסימון גמיש אחד שמתאים לכל התרחישים: /* * Slide In - אנימציית שקופיות כיוונית * השתמש ב--kf-slide-from כדי לשלוט בכיוון * ברירת מחדל: מחליק פנימה משמאל (-100%) *שימוש: * אנימציה: קפ-slide-in 0.3s ease-out; * --kf-slide-from: -100px 0; // החלק משמאל * --kf-slide-from: 100px 0; // החלק מימין * --kf-slide-from: 0 -50px; // החלק מלמעלה */
@keyframes kf-slide-in { מאת { translate: var(--kf-slide-from, -100% 0); } אל { תרגם: 0 0; } }
כעת נוכל להשתמש באסימון @keyframes הבודד הזה לכל כיוון שקף פשוט על ידי שינוי המאפיין --kf-slide-from המותאם אישית: .sidebar { אנימציה: ease-out kf-slide-in 0.3s; /* משתמש בערך ברירת מחדל: שקופיות משמאל */ }
.notification { אנימציה: קפ-החלקה-אין 0.4 שניות קלות החוצה; --kf-slide-from: 0 -50px; /* החלק מלמעלה */ }
.modal { אנימציה: kf-fade-in 0.5s, kf-slide-in 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); --kf-slide-from: 50px 50px; /* החלק מימין למטה */ }
גישה זו מעניקה לנו גמישות מדהימה תוך שמירה על עקביות. הצהרת מסגרת מפתח אחת, אינסוף אפשרויות. ראה את אסימוני ה-Pen Keyframes - הדגמה 3 [מזלג] מאת עמית שין. ואם אנחנו רוצים להפוך את האנימציות שלנו לגמישות עוד יותר, ולאפשר גם אפקטים "מחליקים החוצה", אנחנו יכוליםפשוט הוסף מאפיין --kf-slide-to מותאם אישית, בדומה למה שנראה בסעיף הבא. מסגרות מפתח זום דו-כיווני אנימציה נפוצה נוספת שמשתכפלת בין פרויקטים היא אפקטי "זום". בין אם מדובר בהגדלה עדינה להודעות טוסט, התקרבות דרמטית למודלים, או אפקט הקטנה עדין של כותרות, אנימציות זום נמצאות בכל מקום. במקום ליצור מסגרות מפתח נפרדות עבור כל ערך קנה מידה, בואו נבנה סט גמיש אחד של מסגרות מפתח עם זום של kf:
/* * זום - אנימציה בקנה מידה * השתמש ב--kf-zoom-from ו--kf-zoom-to כדי לשלוט בערכי קנה המידה * ברירת מחדל: זום מ-80% ל-100% (0.8 עד 1) *שימוש: * אנימציה: הקלה על kf-zoom 0.2s; * --kf-zoom-from: 0.5; --kf-zoom-to: 1; // זום מ-50% ל-100% * --kf-zoom-from: 1; --kf-zoom-to: 0; // זום מ-100% ל-0% * --kf-zoom-from: 1; --kf-zoom-to: 1.1; // זום מ-100% ל-110% */
@keyframes kf-zoom { מאת { scale: var(--kf-zoom-from, 0.8); } אל { scale: var(--kf-zoom-to, 1); } }
עם הגדרה אחת, נוכל להשיג כל וריאציה של זום שאנו צריכים: .toast { אנימציה: kf-slide-in 0.2s, קפ-זום 0.4s קלות החוצה; --kf-slide-from: 0 100%; /* החלק מלמעלה */ /* משתמש ברירת המחדל של זום: קנה מידה מ-80% ל-100% */ }
.modal { אנימציה: kf-zoom 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); --kf-zoom-from: 0; /* זום דרמטי מ-0% ל-100% */ }
.heading { אנימציה: kf-fade-in 2s, הקלת kf-zoom 2s; --kf-zoom-from: 1.2; --kf-zoom-to: 0.8; /* הקטנה עדינה */ }
ברירת המחדל של 0.8 (80%) עובדת בצורה מושלמת עבור רוב רכיבי ממשק המשתמש, כמו הודעות טוסט וכרטיסים, ועדיין קלה להתאמה אישית למקרים מיוחדים. ראה את אסימוני ה-Pen Keyframes - הדגמה 4 [מזלג] מאת עמית שין. אולי שמתם לב למשהו מעניין בדוגמאות האחרונות: שילבנו אנימציות. אחד היתרונות המרכזיים בעבודה עם אסימוני @keyframes הוא שהם נועדו להשתלב בצורה חלקה אחד עם השני. הרכב חלק זה הוא מכוון, לא מקרי. נדון בהרכב האנימציה בפירוט רב יותר מאוחר יותר, כולל היכן הם יכולים להפוך לבעייתיים, אך רוב השילובים הם פשוטים וקלים ליישום. הערה: בזמן כתיבת המאמר הזה, ואולי בגלל כתיבתו, מצאתי את עצמי חושב מחדש על כל הרעיון של אנימציות כניסה. עם כל ההתקדמות האחרונה ב-CSS, האם אנחנו עדיין צריכים אותם בכלל? למרבה המזל, אדם ארגייל חקר את אותן שאלות וביטא אותן בצורה מבריקה בבלוג שלו. זה לא סותר את מה שכתוב כאן, אבל זה מציג גישה שכדאי לשקול, במיוחד אם הפרויקטים שלך מסתמכים במידה רבה על אנימציות כניסה. אנימציות מתמשכות בעוד שהנפשות כניסה, כמו "דעיכה", "החלקה" ו"זום" קורות פעם אחת ואז נעצרות, אנימציות מתמשכות עוברות לולאה ללא הגבלת זמן כדי למשוך תשומת לב או להצביע על פעילות מתמשכת. שתי האנימציות הרציפות הנפוצות ביותר שאני נתקל בהן הן "ספין" (עבור מחווני טעינה) ו"פולס" (להדגשת אלמנטים חשובים). אנימציות אלו מציגות אתגרים ייחודיים בכל הנוגע ליצירת אסימוני מפתח פריימים. שלא כמו אנימציות כניסה שעוברות בדרך כלל ממצב אחד לאחר, אנימציות רציפות צריכות להיות ניתנות להתאמה אישית מאוד בדפוסי ההתנהגות שלהן. דוקטור הספין נראה שכל פרויקט משתמש בהנפשות ספין מרובות. חלקם מסתובבים עם כיוון השעון, אחרים נגד כיוון השעון. חלקם עושים סיבוב בודד של 360 מעלות, אחרים עושים סיבובים מרובים לאפקט מהיר יותר. במקום ליצור מסגרות מפתח נפרדות לכל וריאציה, בואו נבנה ספין גמיש אחד שמטפל בכל התרחישים:
/* * ספין - אנימציית סיבוב * השתמש ב--kf-spin-from ו--kf-spin-to כדי לשלוט בטווח הסיבוב * השתמש ב--kf-spin-turns כדי לשלוט בכמות הסיבוב * ברירת מחדל: מסתובב מ-0 מעלות ל-360 מעלות (סיבוב מלא אחד) *שימוש: * אנימציה: kf-spin 1s ליניארי אינסופי; * --kf-spin-turns: 2; // 2 סיבובים מלאים * --kf-spin-from: 0deg; --kf-spin-to: 180 מעלות; // חצי סיבוב * --kf-spin-from: 0deg; --kf-spin-to: -360deg; // נגד כיוון השעון */
@keyframes kf-spin { מאת { סובב: var(--kf-spin-from, 0deg); } אל { rotate: calc(var(--kf-spin-from, 0deg) + var(--kf-spin-to, 360deg) * var(--kf-spin-turns, 1)); } }
עכשיו אנחנו יכולים ליצור כל וריאציה ספין שאנחנו אוהבים:
.loading-spinner { אנימציה: kf-spin 1s ליניארי אינסופי; /* משתמש בברירת מחדל: מסתובב מ-0 מעלות ל-360 מעלות */ }
.fast-loader { אנימציה: kf-spin 1.2s קלות-in-out חלופית אינסופית; --kf-ספין-סיבובים: 3; /* 3 סיבובים מלאים לכל כיוון למחזור*/ }
.steped-reverse { אנימציה: kf-spin 1.5s steps(8) אינסופי; --kf-spin-to: -360deg; /* נגד כיוון השעון */ }
.subtle-wiggle { אנימציה: kf-spin 2s קלות-in-out חלופית אינסופית; --kf-spin-from: -16deg; --kf-spin-to: 32 מעלות; /* התנועע 36 מעלות: בין -18 מעלות ל-+18 מעלות */ }
ראה את אסימוני ה-Pen Keyframes - הדגמה 5 [מזלג] מאת עמית שין. היופי בגישה זו הוא שאותן פריים מפתח פועלות לטעינת ספינרים, אייקונים מסתובבים, אפקטי תנועות, ואפילו אנימציות מורכבות מרובי פניות. פרדוקס הדופק אנימציות דופק מסובכות יותר מכיוון שהן יכולות "לפעום" מאפיינים שונים. חלקם מפעימים את הסולם, אחרים מפעימים את האטימות, וחלקם מפעימים מאפייני צבע כמו בהירות או רוויה. במקום ליצור מסגרות מפתח נפרדות עבור כל מאפיין, אנו יכולים ליצור מסגרות מפתח שעובדות עם כל מאפיין CSS. הנה דוגמה לפריים מפתח דופק עם אפשרויות קנה מידה ואטימות:
/* * Pulse - אנימציה מפעימה * השתמש ב--kf-pulse-scale-from ו--kf-pulse-scale-to כדי לשלוט בטווח קנה המידה * השתמש ב--kf-pulse-opacity-from ו--kf-pulse-opacity-to כדי לשלוט בטווח האטימות * ברירת מחדל: ללא דופק (כל הערכים 1) *שימוש: * אנימציה: kf-pulse 2s קלות-in-out חלופיות אינסופיות; * --kf-pulse-scale-מ: 0.95; --kf-pulse-scale-to: 1.05; // דופק בקנה מידה * --kf-פולס-אטימות-מ: 0.7; --kf-pulse-opacity-to: 1; // דופק אטימות */
@keyframes kf-pulse { מאת { scale: var(--kf-pulse-scale-from, 1); אטימות: var(--kf-pulse-opacity-from, 1); } אל { scale: var(--kf-pulse-scale-to, 1); אטימות: var(--kf-pulse-opacity-to, 1); } }
זה יוצר דופק גמיש שיכול להנפיש מאפיינים מרובים: .call-to-action { אנימציה: kf-pulse 0.6s אינסופי חלופי; --kf-פולס-אטימות-מ: 0.5; /* דופק אטימות */ }
.notification-dot { אנימציה: kf-pulse 0.6s קלות-in-out חלופית אינסופית; --kf-pulse-scale-מ: 0.9; --kf-pulse-scale-to: 1.1; /* דופק סולם */ }
.text-highlight { אנימציה: kf-pulse 1.5s ease-out אינסופי; --kf-pulse-scale-מ: 0.8; --kf-pulse-אטימות-מ: 0.2; /* דופק קנה מידה ואטימות */ }
ראה את אסימוני ה-Pen Keyframes - הדגמה 6 [מזלג] מאת עמית שין. מסגרת מפתח יחידה זו של kf-pulse יכולה להתמודד עם כל דבר, החל מתפיסת תשומת לב עדינה ועד הדגשות דרמטיות, וכל זאת תוך קלה להתאמה אישית. הקלה מתקדמת אחד הדברים הגדולים בשימוש באסימוני Keyframes הוא כמה קל להרחיב את ספריית האנימציה שלנו ולספק אפקטים שרוב המפתחים לא יטרחו לכתוב מאפס, כמו אלסטי או קפיצה. הנה דוגמה לאסימון מפתח פריימים פשוט "הקפיץ" המשתמש במאפיין --kf-bounce-from מותאם אישית כדי לשלוט בגובה הקפיצה. /* * Bounce - אנימציית כניסה מקפיצה * השתמש ב--kf-bounce-from כדי לשלוט בגובה הקפיצה * ברירת מחדל: קופץ מ-100 וולט (מחוץ למסך) *שימוש: * אנימציה: קלה-אין של kf-bounce 3s; * --kf-bounce-from: 200px; // קפוץ מגובה של 200 פיקסלים */
@keyframes kf-bounce { 0% { translate: 0 calc(var(--kf-bounce-from, 100vh) * -1); }
34% { translate: 0 calc(var(--kf-bounce-from, 100vh) * -0.4); }
55% { translate: 0 calc(var(--kf-bounce-from, 100vh) * -0.2); }
72% { translate: 0 calc(var(--kf-bounce-from, 100vh) * -0.1); }
85% { translate: 0 calc(var(--kf-bounce-from, 100vh) * -0.05); }
94% { translate: 0 calc(var(--kf-bounce-from, 100vh) * -0.025); }
99% { translate: 0 calc(var(--kf-bounce-from, 100vh) * -0.0125); }
22%, 45%, 64%, 79%, 90%, 97%, 100% { תרגם: 0 0; אנימציה-תזמון-פונקציה: ease-out; } }
אנימציות כמו "אלסטיות" קצת יותר מסובכות בגלל החישובים בתוך ה-keyframes. אנחנו צריכים להגדיר -kf-elastic-from-X ו--kf-elastic-from-Y בנפרד (שניהם אופציונליים), ויחד הם מאפשרים לנו ליצור כניסה אלסטית מכל נקודה על המסך.
/* * Elastic In - אנימציית כניסה אלסטית * השתמש ב--kf-elastic-from-X ו--kf-elastic-from-Y כדי לשלוט בעמדת ההתחלה * ברירת מחדל: נכנס מהמרכז העליון (0, -100vh) *שימוש: * אנימציה: kf-elastic-in 2s ease-in-out שניהם; * --kf-elastic-from-X: -50px; * --kf-elastic-from-Y: -200px; // enter from (-50px, -200px) */
@keyframes kf-elastic-in { 0% { translate: calc(var(--kf-elastic-from-X, -50vw) * 1) calc(var(--kf-elastic-from-Y, 0px) * 1); }
16% { translate: calc(var(--kf-elastic-from-X, -50vw) * -0.3227) calc(var(--kf-elastic-from-Y, 0px) * -0.3227); }
28% { תרגם: calc(var(--kf-elastic-from-X, -50vw) * 0.1312)calc(var(--kf-elastic-from-Y, 0px) * 0.1312); }
44% { translate: calc(var(--kf-elastic-from-X, -50vw) * -0.0463) calc(var(--kf-elastic-from-Y, 0px) * -0.0463); }
59% { translate: calc(var(--kf-elastic-from-X, -50vw) * 0.0164) calc(var(--kf-elastic-from-Y, 0px) * 0.0164); }
73% { translate: calc(var(--kf-elastic-from-X, -50vw) * -0.0058) calc(var(--kf-elastic-from-Y, 0px) * -0.0058); }
88% { translate: calc(var(--kf-elastic-from-X, -50vw) * 0.0020) calc(var(--kf-elastic-from-Y, 0px) * 0.0020); }
100% { תרגם: 0 0; } }
גישה זו מקלה על שימוש חוזר והתאמה אישית של מסגרות מפתח מתקדמות בפרויקט שלנו, רק על ידי שינוי מאפיין מותאם אישית יחיד.
.bounce-and-zoom { אנימציה: הקלת kf-bounce 3s, kf-zoom 3s ליניארי; --kf-zoom-from: 0; }
.bounce-and-slide { אנימציה-קומפוזיציה: הוסף; /* שתי האנימציות משתמשות בתרגום */ אנימציה: הקלת kf-bounce 3s, kf-slide-in 3s קלות החוצה; --kf-slide-from: -200px; }
.elastic-in { אנימציה: kf-elastic-in 2s ease-in-out שניהם; }
ראה את אסימוני ה-Pen Keyframes - הדגמה 7 [מזלג] מאת עמית שין. עד לנקודה זו, ראינו כיצד אנו יכולים לאחד מסגרות מפתח בצורה חכמה ויעילה. כמובן, אולי תרצה לשנות דברים כדי שיתאימו טוב יותר לצרכי הפרויקט שלך, אבל כיסינו דוגמאות לכמה אנימציות נפוצות ומקרי שימוש יומיומי. ועם אסימוני הפריימים האלה במקום, יש לנו כעת אבני בניין עוצמתיות ליצירת אנימציות עקביות וניתנות לתחזוקה לאורך כל הפרויקט. לא עוד מסגרות מפתח משוכפלות, לא עוד התנגשויות היקף גלובליות. פשוט דרך נקייה ונוחה לטפל בכל צרכי האנימציה שלנו. אבל השאלה האמיתית היא: איך אנחנו מחברים את אבני הבניין האלה ביחד? לשים הכל ביחד ראינו ששילוב של אסימוני מסגרות מפתח בסיסיים הוא פשוט. אנחנו לא צריכים שום דבר מיוחד אלא להגדיר את האנימציה הראשונה, להגדיר את השנייה, להגדיר את המשתנים לפי הצורך, וזהו. /* דהייה + החלק פנימה */ .toast { אנימציה: kf-fade-in 0.4s, kf-slide-in 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); --kf-slide-from: 0 40px; }
/* התקרב + דהייה */ .modal { אנימציה: kf-fade-in 0.3s, kf-zoom 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); --kf-zoom-from: 0.7; --kf-zoom-to: 1; }
/* החלק פנימה + דופק */ .notification { אנימציה: kf-slide-in 0.5s, kf-pulse 1.2s הקלה-in-out חלופית אינסופית; --kf-slide-from: -100px 0; --kf-pulse-scale-מ: 0.95; --kf-pulse-scale-to: 1.05; }
השילובים האלה עובדים יפה כי כל אנימציה מכוונת למאפיין אחר: אטימות, טרנספורמציה (תרגום/קנה מידה) וכו'. אבל לפעמים יש קונפליקטים, ואנחנו צריכים לדעת למה ואיך להתמודד איתם. כאשר שתי אנימציות מנסות להנפיש את אותו מאפיין - למשל, שתיהן קנה מידה הנפשה או שתיהן אטימות הנפשה - התוצאה לא תהיה מה שאתה מצפה. כברירת מחדל, רק אחת מהאנימציות מוחלת בפועל על אותו מאפיין, שהיא האחרונה ברשימת ההנפשות. זוהי מגבלה של האופן שבו CSS מטפל במספר אנימציות באותו מאפיין. לדוגמה, זה לא יעבוד כמתוכנן מכיוון שרק אנימציית kf-pulse תחול. .bad-combo { אנימציה: kf-zoom 0.5 שניות קדימה, kf-pulse 1.2s אינסופי חלופי; --kf-zoom-from: 0.5; --kf-zoom-to: 1.2; --kf-pulse-scale-מ: 0.8; --kf-pulse-scale-to: 1.1; }
תוספת אנימציה הדרך הפשוטה והישירה ביותר לטפל במספר אנימציות שמשפיעות על אותו מאפיין היא להשתמש במאפיין אנימציה-קומפוזיציה. בדוגמה האחרונה למעלה, אנימציית kf-pulse מחליפה את הנפשת kf-zoom, כך שלא נראה את הזום הראשוני ולא נקבל את הקנה המידה הצפוי ל-1.2. על ידי הגדרת הרכב האנימציה להוספה, אנו אומרים לדפדפן לשלב את שתי האנימציות. זה נותן לנו את התוצאה שאנחנו רוצים. .component-two { אנימציה-קומפוזיציה: הוסף; }
ראה את אסימוני ה-Pen Keyframes - הדגמה 8 [מזלג] מאת עמית שין. גישה זו עובדת היטב עבור רוב המקרים בהם אנו רוצים לשלב אפקטים על אותו נכס. זה שימושי גם כשאנחנו צריכים לשלב אנימציות עם ערכי מאפיינים סטטיים. לדוגמה, אם יש לנו אלמנט שמשתמש במאפיין translate כדי למקם אותו בדיוק היכן שאנחנו רוצים, ואז אנחנו רוצים להנפיש אותו עם ה-kf-slide-in keyframes, נקבל קפיצה נראית לעין ללא הנפשה-קומפוזיציה. ראה את אסימוני ה-Pen Keyframes - הדגמה 9 [מזלג] מאת עמית שין. עם הוספת קומפוזיציה אנימציה, האנימציה משולבת בצורה חלקה עם הקייםטרנספורמציה, כך שהאלמנט נשאר במקומו ומפעיל הנפשה כצפוי. סטגר אנימציה דרך נוספת להתמודד עם מספר אנימציות היא "לסמן" אותן - כלומר, להתחיל את האנימציה השנייה מעט אחרי שהראשונה מסתיימת. זה לא פתרון שעובד עבור כל מקרה, אבל הוא שימושי כשיש לנו אנימציית כניסה ואחריה אנימציה רציפה. /* דהייה + דופק אטימות */ .notification { אנימציה: קפ-דעוך-אין 2s ease-out, kf-pulse 0.5s 2s ease-in-out חלופי אינסופי; --kf-pulse-opacity-to: 0.5; }
ראה את אסימוני ה-Pen Keyframes - הדגמה 10 [מזלג] מאת עמית שין. סדר משנה חלק גדול מהאנימציות שאנו עובדים איתן משתמשות במאפיין transform. ברוב המקרים זה פשוט יותר נוח. יש לו גם יתרון ביצועים שכן ניתן להאיץ את הנפשת השינוי ב-GPU. אבל אם אנו משתמשים בטרנספורמציות, עלינו לקבל שהסדר שבו אנו מבצעים את השינויים שלנו חשוב. הרבה. במסגרות המפתח שלנו עד כה, השתמשנו בהמרות בודדות. על פי המפרט, אלה מיושמים תמיד בסדר קבוע: ראשית, האלמנט מקבל תרגום, ואז מסתובב, ואז קנה מידה. זה הגיוני וזה מה שרובנו מצפים. עם זאת, אם נשתמש במאפיין טרנספורמציה, הסדר שבו נכתבות הפונקציות הוא הסדר שבו הן מיושמות. במקרה זה, אם נזיז משהו ב-100 פיקסלים על ציר ה-X ואז נסובב אותו ב-45 מעלות, זה לא זהה לסיבוב הראשון ב-45 מעלות ואז מזיז אותו ב-100 פיקסלים. /* ריבוע ורוד: תחילה תרגם, ואז סובב */ .example-one { transform: translateX(100px) rotate(45deg); }
/* ריבוע ירוק: תחילה סובב, ואז תרגם */ .example-two { transform: rotate(45deg) translateX(100px); }
ראה את אסימוני ה-Pen Keyframes - הדגמה 11 [מזלג] מאת עמית שין. אבל לפי סדר הטרנספורמציה, כל הטרנספורמציות בודדות - כל מה שהשתמשנו עבור אסימוני ה-keyframes - מתרחשות לפני פונקציות הטרנספורמציה. זה אומר שכל מה שתגדירו במאפיין הטרנספורמציה יקרה לאחר ההנפשות. אבל אם תגדיר, למשל, תרגום יחד עם ה-kf-spin keyframes, התרגום יתרחש לפני האנימציה. עדיין מבולבל?! זה מוביל למצבים שבהם ערכים סטטיים יכולים לגרום לתוצאות שונות עבור אותה אנימציה, כמו במקרה הבא:
/* אנימציה משותפת לשני הספינרים */ .spinner { אנימציה: kf-spin 1s ליניארי אינסופי; }
/* ספינר ורוד: תרגם לפני סיבוב (טרנספורמציה בודדת) */ .spinner-pink { תרגם: 100% 50%; }
/* ספינר ירוק: סובב ואז תרגם (סדר פונקציות) */ .spinner-green { transform: translate(100%, 50%); }
ראה את אסימוני ה-Pen Keyframes - הדגמה 12 [מזלג] מאת עמית שין. אתה יכול לראות שהספינר הראשון (ורוד) מקבל תרגום שקורה לפני הסיבוב של kf-ספין, אז הוא קודם כל זז למקומו ואז מסתובב. הספינר השני (ירוק) מקבל פונקציה translate() שמתרחשת לאחר הטרנספורמציה הבודדת, אז האלמנט מסתובב תחילה, ואז זז ביחס לזווית הנוכחית שלו, ואנו מקבלים את אפקט המסלול הרחב הזה. לא, זה לא באג. זה רק אחד מאותם דברים שאנחנו צריכים לדעת על CSS ולזכור כשעובדים עם מספר אנימציות או טרנספורמציות מרובות. במידת הצורך, תוכל גם ליצור קבוצה נוספת של מסגרות מפתח מסוג kf-spin-alt המסובבות אלמנטים באמצעות הפונקציה rotate() . תנועה מופחתת ובעוד אנחנו מדברים על מסגרות מפתח חלופיות, אנחנו לא יכולים להתעלם מהאפשרות "ללא אנימציה". אחד היתרונות הגדולים ביותר של שימוש באסימוני Keyframes הוא שניתן לאפות את הנגישות, ולמעשה די קל לעשות זאת. על ידי עיצוב ה-keyframes שלנו עם נגישות בחשבון, אנו יכולים להבטיח שמשתמשים המעדיפים תנועה מופחתת יקבלו חוויה חלקה יותר, פחות מסיחה את הדעת, ללא עבודה נוספת או שכפול קוד. המשמעות המדויקת של "תנועה מופחתת" יכולה להשתנות מעט מאנימציה אחת לאחרת ומפרויקט לפרויקט, אבל הנה כמה נקודות חשובות שכדאי לזכור: השתקת Keyframes בעוד שחלק מהאנימציות ניתנות לריכוך או להאט, יש אחרות שאמורות להיעלם לחלוטין כאשר מתבקשת תנועה מופחתת. אנימציות דופק הן דוגמה טובה. כדי לוודא שהאנימציות האלה לא יפעלו במצב תנועה מופחתת, אנחנו יכולים פשוט לעטוף אותן בשאילתת המדיה המתאימה.
@media (prefers-reduced-motion: no-preference) { @keyfrmaes kf-pulse { מאת { scale: var(--kf-pulse-scale-from, 1); אטימות: var(--kf-pulse-opacity-from, 1); } אל { scale: var(--kf-pulse-scale-to, 1); אֲטִימוּת:var(--kf-pulse-opacity-to, 1); } } }
זה מבטיח שמשתמשים שהגדירו תנועה מופחתת להפחתה לא יראו את האנימציה ויקבלו חוויה שתואמת את העדפתם. Instant In יש כמה פריים מפתח שאנחנו לא יכולים פשוט להסיר, כמו אנימציות כניסה. הערך חייב להשתנות, חייב להחיות; אחרת, לאלמנט לא יהיו הערכים הנכונים. אבל בתנועה מופחתת, המעבר הזה מהערך ההתחלתי צריך להיות מיידי. כדי להשיג זאת, נגדיר קבוצה נוספת של מסגרות מפתח שבהן הערך קופץ מיד למצב הסיום. אלה הופכים למסגרות מפתח ברירת המחדל שלנו. לאחר מכן, נוסיף את ה-keyframes הרגילים בתוך שאילתת מדיה עבור prefers-reduced-motion מוגדר ללא העדפה, בדיוק כמו בדוגמה הקודמת. /* נכנסים מיד להפחתת תנועה */ @keyframes kf-zoom { מ, אל { scale: var(--kf-zoom-to, 1); } }
@media (prefers-reduced-motion: no-preference) { /* מסגרות מפתח זום מקוריות */ @keyframes kf-zoom { מאת { scale: var(--kf-zoom-from, 0.8); } אל { scale: var(--kf-zoom-to, 1); } } }
בדרך זו, משתמשים המעדיפים תנועה מופחתת יראו את האלמנט מופיע באופן מיידי במצבו הסופי, בעוד שכולם מקבלים את המעבר המונפש. הגישה הרכה יש מקרים שבהם אנחנו כן רוצים לשמור על קצת תנועה, אבל הרבה יותר רכה ורגועה מהאנימציה המקורית. לדוגמה, נוכל להחליף כניסה מקפיצה בפייד-אין עדין.
@keyframes kf-bounce { /* דהייה רכה להפחתת תנועה */ }
@media (prefers-reduced-motion: no-preference) { @keyframes kf-bounce { /* מסגרות מפתח מקוריות להקפיץ */ } }
כעת, משתמשים עם תנועה מופחתת מופעלת עדיין מקבלים תחושה של מראה, אך ללא תנועה אינטנסיבית של הקפצה או אנימציה אלסטית. עם אבני הבניין במקום, השאלה הבאה היא איך להפוך אותם לחלק מתהליך העבודה בפועל. כתיבת מסגרות מפתח גמישות היא דבר אחד, אבל הפיכתן לאמינות בפרויקט גדול דורשת כמה אסטרטגיות שהייתי צריך ללמוד בדרך הקשה. אסטרטגיות יישום ושיטות עבודה מומלצות ברגע שיש לנו ספרייה מוצקה של אסימוני מפתחי מפתח, האתגר האמיתי הוא איך להביא אותם לעבודה היומיומית.
הפיתוי הוא להפיל את כל הפריימים בבת אחת ולהכריז שהבעיה נפתרה, אבל בפועל גיליתי שהתוצאות הטובות ביותר מגיעות מאימוץ הדרגתי. התחל עם האנימציות הנפוצות ביותר, כגון דהייה או שקף. אלו זכיות קלות שמראות ערך מיידי מבלי לדרוש שכתובים גדולים. מתן שמות הוא נקודה נוספת שראויה לתשומת לב. קידומת עקבית או מרחב שמות מבהירים אילו אנימציות הן אסימונים ואילו הן חד-פעמיות מקומיות. זה גם מונע התנגשויות מקריות ומסייע לחברי צוות חדשים לזהות את המערכת המשותפת במבט חטוף. התיעוד חשוב לא פחות מהקוד עצמו. אפילו הערה קצרה מעל כל אסימון מפתחות יכולה לחסוך שעות של ניחושים מאוחר יותר. מפתח אמור להיות מסוגל לפתוח את קובץ האסימונים, לסרוק את האפקט הדרוש לו ולהעתיק את תבנית השימוש היישר לרכיב שלו. גמישות היא מה שהופך את הגישה הזו לשווה את המאמץ. על ידי חשיפת מאפיינים מותאמים אישית הגיוניים, אנו נותנים לצוותים מקום להתאים את האנימציה מבלי לשבור את המערכת. יחד עם זאת, נסו לא לסבך יתר על המידה. ספקו את הכפתורים החשובים והשאירו את השאר דעתניים. לבסוף, זכרו את הנגישות. לא כל אנימציה זקוקה לחלופת תנועה מופחתת, אבל רבים כן. אפייה מוקדמת בהתאמות הללו פירושה שלעולם לא נצטרך להתאים אותן מאוחר יותר, וזה מראה על רמת זהירות שהמשתמשים שלנו ישימו לב אליה גם אם לא יזכירו זאת לעולם.
מניסיוני, התייחסות לאסימוני Keyframes כחלק מזרימת העבודה של אסימוני העיצוב שלנו היא מה שגורם להם להיצמד. ברגע שהם במקום, הם מפסיקים להרגיש כמו אפקטים מיוחדים והופכים לחלק מהשפה העיצובית, שלוחה טבעית של איך המוצר זז ומגיב. מסכם אנימציות יכולות להיות אחד החלקים המשמחים ביותר בבניית ממשקים, אך ללא מבנה, הן גם יכולות להפוך לאחד ממקורות התסכול הגדולים ביותר. על ידי התייחסות לפריימים מפתח כאל אסימונים, אתה לוקח משהו שבדרך כלל מבולגן וקשה לניהול והופכים אותו למערכת ברורה וצפויה. הערך האמיתי הוא לא רק בשמירת כמה שורות קוד. זה מתוך ביטחון שכאשר אתה משתמש בדעיכה, שקף, זום או ספין, אתה יודע בדיוק איך זה יתנהג לאורך הפרויקט. זה בגמישות שמגיעה ממאפיינים מותאמים אישית ללא הכאוס של וריאציות אינסופיות. וזה בנגישות המובנית בבסיס ולא מתווסף כמומחשבה שלאחר מכן. ראיתי את הרעיונות האלה עובדים בצוותים שונים ובבסיסי קוד שונים, והתבנית תמיד זהה. ברגע שהאסימונים נמצאים במקומם, מפתחי מפתח מפסיקים להיות אוסף מפוזר של טריקים והופכים לחלק מהשפה העיצובית. הם גורמים למוצר להרגיש יותר מכוון, עקבי יותר וחי יותר. אם אתה לוקח דבר אחד מהמאמר הזה, תן לזה להיות זה: אנימציות ראויות לאותו טיפול ומבנה שאנחנו כבר נותנים לצבעים, טיפוגרפיה ומרווחים. השקעה קטנה באסימוני keyframes משתלמת בכל פעם שהממשק שלך זז.