חיפוש ]

התכונה property@ ב-CSS: מדריך מקיף עם דוגמאות חיות

"כלל ה-@property מעניק למשתני CSS יכולת שמעולם לא הייתה להם: מערכת טיפוסים (Type System). כעת אפשר להגדיר לדפדפן שמשתנה מסוים הוא צבע, זווית או אורך, ופתאום דברים כמו אנימציות גרדיאנט (gradients) או אנימציות ל borders למשל פשוט עובדים.

אני התחלתי להשתמש ב-@property אחרי ששרפתי יותר מדי זמן בניסיון לחקות אנימציות גרדיאנט באמצעות pseudo-elements ומשחקי שקיפות. ברגע שהגדרתי את צבעי הגרדיאנט כמשתנים בעלי טיפוס (type), הדפדפן ביצע את האינטרפולציה באופן מובנה. בלי JavaScript, ובלי ״קומבינות״.

מה זה property@?

משתני CSS רגילים (Custom Properties) מטופלים כמחרוזות על ידי הדפדפן. הוא שומר את --brand-color: #3490dc כערך טקסט גולמי. המשמעות היא שהדפדפן לא יכול לבצע אינטרפולציה בין שני ערכים במהלך מעבר כי הוא לא יודע איזה סוג נתונים הוא מחזיק.

@property פותר את זה על ידי כך שמאפשר לרשום custom property עם שלושה פרטים:

  • syntax – סוג הנתונים (<color>, <angle>, <length>, <number> וכו')
  • initial-value – ערך ברירת מחדל כ-fallback
  • inherits – האם אלמנטים ילדים יורשים את הערך
@property --brand-color {
  syntax: "<color>";
  inherits: true;
  initial-value: #3490dc;
}

שלושת המתארים נדרשים (למעט initial-value כאשר ה-syntax הוא "*").

מתאר ה-Syntax

מתאר ה-syntax מגדיר אילו ערכים התכונה מקבלת. הנה הטיפוסים הנתמכים:

<>דוגמה

Syntaxמקבל
<color>כל צבע תקין#ff0, rgb(0 0 0), hsl(120 50% 50%)
<length>אורכים עם יחידות16px, 2rem, 50vw
<number>מספרים ללא יחידות0, 1.5, 42
<percentage>ערכי אחוזים50%, 100%
<angle>ערכי זווית45deg, 0.5turn, 3.14rad
<integer>מספרים שלמים בלבד0, 3, -1
<time>ערכי משך זמן300ms, 1.5s
<image>הפניות לתמונות/gradientsurl(...), linear-gradient(...)
<transform-function>פונקציות transformrotate(45deg), scale(1.2)
"*"כל ערך (אוניברסלי)כל ערך CSS תקין

ניתן גם לשלב טיפוסים עם | לחלופות: "<color> | <length>". או להשתמש ב-+ ו-# לרשימות מופרדות ברווח ובפסיקים.

למה זה חשוב: הנפשה של הבלתי אפשרי

זו התכונה שהופכת את @property לשווה למידה. בלעדיה, הדפדפן לא יכול לבצע transition על gradients כי הוא רואה אותם כמחרוזות אטומות. עם typed properties, הוא יכול לבצע אינטרפולציה על כל color stop בנפרד.

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

Without @property hover me
With @property hover me

הכרטיס השמאלי משתמש ב-transition: background רגיל. בעת hover, ה-gradient קופץ מיידית כי הדפדפן לא יכול לבצע אינטרפולציה בין שתי מחרוזות gradient. הכרטיס הימני רושם כל color stop עם @property כ-<color>, כך שהדפדפן מבצע transition חלק.

הנה הקוד לגרסה החלקה:

@property --grad-start {
  syntax: "<color>";
  inherits: false;
  initial-value: #3490dc;
}
@property --grad-end {
  syntax: "<color>";
  inherits: false;
  initial-value: #6574cd;
}

.card {
  background: linear-gradient(135deg, var(--grad-start), var(--grad-end));
  transition: --grad-start 0.8s ease, --grad-end 0.8s ease;
}
.card:hover {
  --grad-start: #e3342f;
  --grad-end: #ffb636;
}

התובנה המרכזית: מבצעים transition על ה-custom property עצמו, לא על ה-background. הדפדפן יודע שהתכונה היא <color>, אז הוא מבצע אינטרפולציה בין שני ערכי הצבע. ה-gradient נבנה מחדש בכל פריים עם הצבעים המעודכנים.

הנפשת זוויות: סיבוב Gradients

אותו עיקרון עובד גם עבור זוויות. רושמים תכונה כ-<angle> ואפשר להנפיש אותה בתוך כלל @keyframes. הדוגמה הזו יוצרת conic gradient מסתובב ברציפות:

Conic gradient
rotating via
@property
@property --rotate-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.spinner {
  background: conic-gradient(
    from var(--rotate-angle),
    #AE0E38, #E57622, #ffb636,
    #3490dc, #6574cd, #AE0E38
  );
  animation: spin 4s linear infinite;
}

@keyframes spin {
  to { --rotate-angle: 360deg; }
}

לפני @property, סיבוב של conic gradient דרש JavaScript או סיבוב של האלמנט כולו עם transform: rotate(). עם תכונת <angle> רשומה, מנפישים רק את זווית ההתחלה של ה-gradient.

מחזור גוונים מונפש

על ידי רישום custom property כ-<number>, ניתן להנפיש אותו ולהזין אותו לתוך hsl(). זה יוצר אפקט גל צבעוני שבו כל תא עובר מחזור גוונים בהיסט שונה:

1
2
3
4
5
6
7
8
@property --hue {
  syntax: "<number>";
  inherits: false;
  initial-value: 220;
}

.cell {
  background: hsl(var(--hue), 65%, 55%);
  animation: hue-cycle 6s ease-in-out infinite alternate;
}
.cell:nth-child(2) { animation-delay: -0.5s; }
.cell:nth-child(3) { animation-delay: -1s; }
/* ... השהיות מדורגות לכל תא */

@keyframes hue-cycle {
  0%   { --hue: 220; }
  50%  { --hue: 340; }
  100% { --hue: 40; }
}

ולידציית טיפוסים ו-Fallbacks בטוחים

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

@property משנה את זה. אם מקצים ערך לא תקין לתכונה רשומה, הדפדפן חוזר ל-initial-value שהגדרנו:

Valid: 24px
--safe-size: 24px
Fallback: 16px
--safe-size: banana
(falls back to initial-value)
@property --safe-size {
  syntax: "<length>";
  inherits: false;
  initial-value: 16px;
}

.element {
  --safe-size: banana;       /* לא תקין עבור <length> */
  font-size: var(--safe-size); /* משתמש ב-16px, לא שבור */
}

שליטה בתורשה

Custom properties רגילים תמיד עוברים בתורשה מאב לילד. עם @property, הגדרת inherits: false מונעת מהערך לזלוג במורד עץ ה-DOM. זה שימושי עבור design tokens בעלי scope שלא צריכים לעבור לרכיבים מקוננים.

inherits: true (ברירת מחדל)
Parent: --theme-accent: #ffb636
הילד יורש את הצבע הזהוב
inherits: false
Parent: --scoped-accent: #75bbe8
הילד מקבל initial-value (#aeafb4)
@property --scoped-accent {
  syntax: "<color>";
  inherits: false;
  initial-value: #aeafb4;
}

.parent {
  --scoped-accent: #75bbe8;  /* חל רק על .parent */
  border-color: var(--scoped-accent); /* כחול */
}

.child {
  border-color: var(--scoped-accent); /* אפור - initial-value */
}

אנימציה על מסגרות

שילוב של @property עם conic-gradient נותן מסגרות gradient מונפשות – ללא צורך בפסאודו-אלמנטים. הטריק: שימוש ב-wrapper חיצוני דק עם gradient מונפש כרקע ואלמנט פנימי עם רקע מלא, שמשאיר רק מרווח של 2px לאפקט המסגרת.

Animated Border

ה-gradient מסתובב סביב הכרטיס באמצעות משתנה זווית יחיד של @property.

@property --border-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.card-wrapper {
  padding: 2px;
  border-radius: 10px;
  background: conic-gradient(
    from var(--border-angle),
    #AE0E38, #E57622, #ffb636, #3490dc, #AE0E38
  );
  animation: border-spin 3s linear infinite;
}

.card-inner {
  background: var(--light-bg);
  border-radius: 8px;
  padding: 24px;
}

@keyframes border-spin {
  to { --border-angle: 360deg; }
}

טכניקה זו עובדת היטב עבור מסגרות gradient שדורשות תנועה.

אנימציה של סרגל התקדמות

רושמים תכונת <percentage> ואפשר להנפיש רוחב בצורה חלקה עם @keyframes:

@property --progress
@property --progress {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

.progress-fill {
  width: var(--progress);
  animation: fill 3s ease-in-out infinite alternate;
}

@keyframes fill {
  0%   { --progress: 5%; }
  100% { --progress: 92%; }
}

property@ מול ()CSS.registerProperty

ניתן גם לרשום תכונות מ-JavaScript באמצעות CSS.registerProperty(). הפונקציונליות זהה, אך יש הבדלים:

תכונהproperty (CSS)@CSS.registerProperty() (JS)
מוצהר ב-קובץ CSSJavaScript
חוסם רינדורלא (מנותח עם ה-CSS)כן (רץ ב-JS)
אפשר לרשום מחדשההגדרה האחרונה גוברתזורק שגיאה אם כבר רשום
ידידותי ל-SSRכןלא (דורש DOM)
CSS.registerProperty({
  name: '--brand-color',
  syntax: '<color>',
  inherits: true,
  initialValue: '#3490dc'
});

העדיפו את ה-at-rule של @property ב-CSS על פני CSS.registerProperty() אלא אם אתם צריכים לרשום תכונות באופן דינמי בזמן ריצה. הגישה ב-CSS מנותחת יחד עם ה-stylesheets ולא דורשת הרצת JavaScript קודם.

תמיכת דפדפנים

@property הגיע לתמיכה אוניברסלית בדפדפנים ביולי 2024:

  • Chrome 85+ (יולי 2020)
  • Edge 85+ (יולי 2020)
  • Safari 16.4+ (מרץ 2023)
  • Firefox 128+ (יולי 2024)

Firefox היה האחרון. עם גרסה 128, התכונה זמינה כעת בכל מקום. ניתן להשתמש ב-@supports כדי לספק fallback לדפדפנים ישנים:

@supports (background: paint(id)) {
  /* @property נתמך */
}

/* או בדיקת תכונה רשומה */
@supports (--test: initial) {
  /* custom properties בסיסיים נתמכים */
}

שאלות נפוצות

שאלות נפוצות על @property:

מה ההבדל בין @property למשתני CSS רגילים?
משתני CSS רגילים (--name: value) הם מחרוזות ללא טיפוס. הדפדפן שומר ומעביר אותם כמות שהם. @property רושם משתנה עם טיפוס מסוים (כמו <color> או <angle>), ערך fallback התחלתי ודגל תורשה. זה נותן לדפדפן מספיק מידע כדי להנפיש את התכונה, לוולדט ערכים שהוקצו ולחזור בצורה אלגנטית כשמשהו לא תקין מוקצה.
אפשר להנפיש gradients עם @property?
כן. רושמים כל color stop כ-@property נפרד עם syntax: "<color>", משתמשים בהם ב-gradient דרך var(), ואז מבצעים transition או animation ישירות על ה-custom properties. הדפדפן מבצע אינטרפולציה בין ערכי הצבע ומייצר מעבר gradient חלק. ללא @property, gradients קופצים מיידית כי הדפדפן רואה אותם כמחרוזות אטומות.
האם כל שלושת המתארים של @property נדרשים?
syntax ו-inherits נדרשים תמיד. initial-value נדרש אלא אם ה-syntax הוא "*" (ה-syntax האוניברסלי). אם משמיטים מתאר נדרש, כל כלל ה-@property לא תקין והדפדפן מתעלם ממנו.
מה קורה כשמקצים ערך לא תקין לתכונה רשומה?
הדפדפן חוזר ל-initial-value שהוגדר בכלל @property. זה שונה מ-custom properties רגילים, שם ערך לא תקין גורם להצהרה להיזרק לגמרי והתכונה מתפרשת לערך הירוש או ההתחלתי שלה. תכונות רשומות נותנות רשת ביטחון אמינה.
להשתמש ב-@property או ב-CSS.registerProperty()?
העדיפו את ה-at-rule של @property ב-CSS ברוב המקרים. הוא מנותח יחד עם ה-stylesheet, לא דורש JavaScript ולא חוסם רינדור. השתמשו ב-CSS.registerProperty() רק כשצריך לרשום תכונות באופן דינמי בזמן ריצה, למשל בהתאם להעדפות משתמש או תצורת A/B testing.
האם @property עובד בכל הדפדפנים?
כן, מאז יולי 2024. Chrome ו-Edge תומכים מגרסה 85 (2020), Safari מגרסה 16.4 (2023), ו-Firefox מגרסה 128 (יולי 2024). זו כעת תכונת Baseline זמינה בכל הדפדפנים המודרניים. בדפדפנים ישנים שלא תומכים, התכונה פשוט מתנהגת כ-custom property רגיל ללא טיפוס.

סיכום

@property ממלא פער אמיתי ב-CSS. לפני שהוא נחת, custom properties היו רק מכולות של מחרוזות. עכשיו הם נושאים מידע על טיפוס שמאפשר אנימציות gradient, fallbacks בטוחים ותורשה מבוקרת – הכל ב-CSS טהור.

אם אתם כבר משתמשים במשתני CSS, @property הוא הצעד הבא. התחילו עם טריק ה-gradient transition כי זה הרווח הנראה ביותר, ואז חקרו typed fallbacks עבור ה-design tokens שלכם.

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

השאירו תגובה

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

Savvy WordPress Development official logo