"כלל ה-@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> | הפניות לתמונות/gradients | url(...), linear-gradient(...) |
<transform-function> | פונקציות transform | rotate(45deg), scale(1.2) |
"*" | כל ערך (אוניברסלי) | כל ערך CSS תקין |
ניתן גם לשלב טיפוסים עם | לחלופות: "<color> | <length>". או להשתמש ב-+ ו-# לרשימות מופרדות ברווח ובפסיקים.
למה זה חשוב: הנפשה של הבלתי אפשרי
זו התכונה שהופכת את @property לשווה למידה. בלעדיה, הדפדפן לא יכול לבצע transition על gradients כי הוא רואה אותם כמחרוזות אטומות. עם typed properties, הוא יכול לבצע אינטרפולציה על כל color stop בנפרד.
העבירו את העכבר מעל שני הכרטיסים כדי לראות את ההבדל:
הכרטיס השמאלי משתמש ב-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 מסתובב ברציפות:
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(). זה יוצר אפקט גל צבעוני שבו כל תא עובר מחזור גוונים בהיסט שונה:
@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 שהגדרנו:
(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 שלא צריכים לעבור לרכיבים מקוננים.
@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 {
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) |
|---|---|---|
| מוצהר ב- | קובץ CSS | JavaScript |
| חוסם רינדור | לא (מנותח עם ה-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 רגילים?
--name: value) הם מחרוזות ללא טיפוס. הדפדפן שומר ומעביר אותם כמות שהם. @property רושם משתנה עם טיפוס מסוים (כמו <color> או <angle>), ערך fallback התחלתי ודגל תורשה. זה נותן לדפדפן מספיק מידע כדי להנפיש את התכונה, לוולדט ערכים שהוקצו ולחזור בצורה אלגנטית כשמשהו לא תקין מוקצה.@property?
@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()?
@property ב-CSS ברוב המקרים. הוא מנותח יחד עם ה-stylesheet, לא דורש JavaScript ולא חוסם רינדור. השתמשו ב-CSS.registerProperty() רק כשצריך לרשום תכונות באופן דינמי בזמן ריצה, למשל בהתאם להעדפות משתמש או תצורת A/B testing.@property עובד בכל הדפדפנים?
סיכום
@property ממלא פער אמיתי ב-CSS. לפני שהוא נחת, custom properties היו רק מכולות של מחרוזות. עכשיו הם נושאים מידע על טיפוס שמאפשר אנימציות gradient, fallbacks בטוחים ותורשה מבוקרת – הכל ב-CSS טהור.
אם אתם כבר משתמשים במשתני CSS, @property הוא הצעד הבא. התחילו עם טריק ה-gradient transition כי זה הרווח הנראה ביותר, ואז חקרו typed fallbacks עבור ה-design tokens שלכם.

