Understanding the @property Variable in CSS
Table of contents
We all know about variables in CSS, which are similar to JavaScript variables in that they store values. However, do you know the downside of CSS variables? It’s the inheritance nature of CSS variables. While inheritance has its advantages, it also comes with some disadvantages.
Advantages:
One of the key advantages is the ability to inherit the value of the nearest defined variable.
Consider the following HTML structure:
<div class="parent">
<div class="child">
<div class="grandChild"></div>
</div>
</div>
And the CSS:
.parent {
--store: 50deg;
}
.grandChild {
width: 50px;
height: 50px;
margin-top: 5rem;
background-color: #522add;
transform: rotate(var(--store));
}
In this case, the --store
variable will inherit its value from the parent element, and the grandChild
element will be rotated by 50 degrees as expected.
Disadvantages:
Now, consider you are collaborating with others on a large project with extensive CSS. Someone might add a variable with the same name but store a different type of value, such as a hex code for a color. This would break the rotate
CSS of the grandChild
since --store
would no longer be a degree value but a color. As a result, the grandChild
element would not rotate.
.parent {
--store: 50deg;
}
.child {
--store: #552ADD;
}
.grandChild {
width: 50px;
height: 50px;
margin-top: 5rem;
background-color: #522add;
transform: rotate(var(--store));
}
This issue can be avoided by using the @property
rule. Let’s see how:
@property --store {
syntax: "<angle>";
inherits: true;
initial-value: 0deg;
}
.parent {
--store: 50deg;
}
.child {
--store: #552ADD;
}
.grandChild {
width: 50px;
height: 50px;
margin-top: 5rem;
background-color: #552ADD;
transform: rotate(var(--store));
}
When declaring the --store
property with @property
, we set the syntax
to "<angle>"
, meaning it can only accept angle values. The inherits
property is set to true
, allowing it to inherit the nearest declared --store
value. We also provide an initial-value
of 0deg
.
Now, even though we have set --store
inside .parent
to 50deg
and --store
inside .child
to #552ADD
, the rotate
CSS of grandChild
will not break. This is because we have defined that --store
should only accept angle values, so the grandChild
will still rotate by 50 degrees. Even though inherits
is set to true
, the invalid value in .child
will be ignored.
Note: If you don’t want the variable to inherit the nearest declared value, you can set the inherits
property to false
. This ensures that even if you update the value in a nearby redeclared variable, the @property
variable will still retain the initial value declared during initialization.
Another Scenario:
Let’s consider another scenario. Imagine you have the following HTML structure:
<div class="parent">
<div class="child">
<div class="grandChild">
<div style="border: 1px solid white"></div>
</div>
</div>
</div>
And you want to animate the rotation of the grandChild
element with the following CSS:
.parent {
--store: 0deg;
}
.child {}
.grandChild {
width: 50px;
height: 50px;
background-color: #552ADD;
animation: spin linear 3s infinite;
transform: rotate(var(--store));
}
@keyframes spin {
0% {
--store: 0deg;
}
20% {
--store: 72deg;
}
40% {
--store: 144deg;
}
60% {
--store: 216deg;
}
80% {
--store: 288deg;
}
100% {
--store: 360deg;
}
}
The problem here is that the element will not rotate smoothly; it will jump from 0 to 72, 72 to 144, and so on.
However, when you use the @property
variable, the element will rotate smoothly, like this:
@property --store {
syntax: "<angle>";
inherits: true;
initial-value: 0deg;
}
.parent {
--store: 0deg;
}
.child {}
.grandChild {
width: 50px;
height: 50px;
background-color: #552ADD;
animation: spin linear 3s infinite;
transform: rotate(var(--store));
}
@keyframes spin {
0% {
--store: 0deg;
}
20% {
--store: 72deg;
}
40% {
--store: 144deg;
}
60% {
--store: 216deg;
}
80% {
--store: 288deg;
}
100% {
--store: 360deg;
}
}
What happens when you use the @property
variable is that, because we defined the syntax
as "<angle>"
, the value of the --store
variable will not jump directly from 0 to 72, 72 to 144, and so on. Instead, it will gradually increment (e.g., 0, 1, 2, 3, up to 360 degrees), creating a smooth, transition-like effect during the rotation. The grandChild
element will rotate smoothly as a result.
Summary
CSS Variables and Inheritance:
CSS variables, like JavaScript variables, store values.
Inheritance allows CSS variables to inherit values from parent elements.
While useful, inheritance can cause issues in large projects if variables with the same name are reused for different purposes.
Limitations:
- If a variable like
--store
is redefined with a different value type (e.g., a color instead of a degree), it can break the intended functionality.
- If a variable like
Using
@property
:The
@property
rule allows you to define the expected syntax, inheritance behavior, and initial value of a CSS variable.This ensures that variables maintain their intended purpose, preventing issues like incorrect value types.
Practical Example:
- The blog demonstrates how using
@property
can prevent issues with variable inheritance and improve the smoothness of CSS animations, ensuring transitions are gradual rather than abrupt.
- The blog demonstrates how using
Additional Note:
- If you don’t want the variable to inherit the nearest declared value, you can set the
inherits
property tofalse
. This ensures that the variable retains its initial value even if it is redeclared nearby.
- If you don’t want the variable to inherit the nearest declared value, you can set the