@property, and extra to kill a tidy streak fabricate that can were extraordinarily advanced to create even about a years ago with out per chance the most contemporary and excellent that CSS has to provide.
In a previous article on CSS-Tricks, I demonstrated tips on how to kill a fancy streak fabricate where an avatar pops out of a circle on streak. The area was to manufacture such an fabricate the employ of most efficient the ticket.
Understand the Pen [Fancy hover effect on avatar](https://codepen.io/t_afif/pen/MWBjraa) by Temani Afif.
That was a fun exercise! I relied on a aggregate of traditional styling strategies intriguing background, outline, and mask to kill the fabricate. This time, I desire to pull off one thing identical while pushing the limits of CSS a cramped extra to kill a extra complex fabricate the employ of about a of the more moderen factors which were released in CSS throughout the last couple of years — issues be pleased shapes made from gradients paired with trigonometric capabilities and custom-made properties.
We’re going to put those ideas to make employ of to increase the remainder demo. As a replacement of a straightforward circle, we are able to non-public a roughly flower form that rotates and… effectively, a demo price a thousand phrases:
Understand the Pen [Fancy Pop Out hover effect!](https://codepen.io/t_afif/pen/qBQzrwq) by Temani Afif.
Frosty, appropriate? We have a fancy form that rotates. On streak, the avatar pops out of the physique, the rotation quickens, and the form is exclusively a cramped modified — all at the identical time. And, it’s price calling out that it’s completed with nothing greater than a single part within the markup. Better yet, we gained’t even be reaching for pseudo-sides, be pleased :before and :after within the process. It’s a big demonstration of what CSS can create this explain day!
I create desire to explain, alternatively, that we’re going to be living on the bleeding edge a cramped. So, while the total ideas we’re covering here are fun, I wouldn’t express that the entire lot is manufacturing-ready at this point, as they non-public got yet to be implemented in a single browser or another. For the sake of demonstration, I counsel viewing the work we create collectively in Chrome or Edge since they invent certainly give a steal to the entire lot we’re discussing.
We’ll sort out this one step at a time, starting with a image against a masked form to kill the physique. From there, we’ll sort out the rotations sooner than topping issues off with the pop-out fabricate from the remainder demo.
Masking The Physique
Let’s initiating by developing a flower form the employ of CSS masks. That is what we are aiming for:

I trace it may per chance probably seem be pleased this form requires developed trickery. But if we ruin it down a cramped, all we’re if truth be told talking about is a series of cramped circles around a necessary better circle.

We’re going to rely on radial-gradient and some math, namely trigonometric capabilities. Bramus Van Damme presents an stunning primer on trigonometric capabilities over at net.dev. It’s very great price your while to brush up on the belief that with that article.
We’re going to make clear two variables to management the flower form. N represents the alternative of the cramped circles, and R is the diameter of the cramped circles (Illustrated by the dim arrow within the figure above). If we have the diameter, then we are able to calculate the radius by dividing R by 2. That is the entire lot we have to kill the form!
Right here’s what the code of a cramped circle looks to be like be pleased:
img {
--r: 50px;
mask:
radial-gradient(#000 70%, #0000 72%) no-repeat
{position} / var(--r) var(--r);
}
All of the cramped circles can employ the identical radial gradient. Essentially the most efficient incompatibility between them is the world. Right here comes the mathematics:
(50% + 50% * cos(360deg * i/N)) (50% + 50% * sin(360deg * i/N))
N is the choice of circles, and i is the index of every circle. Shall we manually area every circle in my conception, however that’s slightly diverse labor, and I feel about in leveraging tools to support create about a of the heavy lifting. So, I’m going to change from CSS to Sass to make employ of its capability to write loops and generate the total circle positions in a single fell swoop.
$n: 15; /* number of circles */
img {
--r: 50px; /* control the small circles radius */
$m: ();
@for $i from 1 through ($n) {
$m: append($m,
radial-gradient(#000 70%,#0000 72%) no-repeat
calc(50% + 50% * cos(360deg * #{$i / $n}))
calc(50% + 50% * sin(360deg * #{$i / $n})) /
var(--r) var(--r),
comma);
}
mask: $m;
}
We’re in fact looping thru the choice of circles ($n) to make clear every individual by chaining the radial gradient for every individual as comma-separated values on the hide ($m) that’s applied to the image part.
We soundless need the fat circle that the cramped circles are positioned around. So, as effectively as to the loop’s output by process of the $m variable, we chain the simpler circle’s gradient on the identical mask declaration:
img {
/* etc */
mask: $m, radial-gradient(#000 calc(72% - var(--r)/2),#0000 0);
}
In the extinguish, we make clear the scale of the image part itself the employ of the identical variables. Calculating the image’s width also requires the employ of trigonometric capabilities. Then, relatively than doing the identical thing for the height, we are able to manufacture employ of the reasonably contemporary aspect-ratio property to obtain a very good 1:1 ratio:
img {
/* etc */
width: calc(var(--r) * (1 + 1/sin(180deg / #{$n})));
aspect-ratio: 1;
}
Compare it out. We have the form we desire and can with out difficulty protect an eye on the scale and alternative of circles with most efficient two variables.
Understand the Pen [Flower shape using CSS Mask](https://codepen.io/t_afif/pen/poQMvbV) by Temani Afif.
Rotating The Shape
Now, let’s rotate the form. The root is to switch the smaller circles all the map thru the greater circle to simulate the rotation of your total form.
To create this, we’re going to animate the attitude. That identical attitude is outdated school to area the circles, so by adjusting it fair a cramped, we kill a circular circulate.
img {
--a: 0deg;
$m: ();
@for $i from 1 through ($n) {
$m: append($m,
radial-gradient(#000 70%, #0000 72%) no-repeat
calc(50% + 50% * cos(360deg * #{$i/$n} + var(--a)))
calc(50% + 50% * sin(360deg * #{$i/$n} + var(--a))) /
var(--r) var(--r),
comma);
}
animation: rotate 10s linear infinite;
/* etc */
}
@keyframes rotate {
to { --a:360deg }
}
That looks tidy complex, appropriate? But if truth be told, it’s the identical equation we had sooner than, however with the addition of a brand contemporary variable that represents the attitude (--a) in degrees and applies an animation on the image. As a replacement of getting a fixed attitude equal to 360deg * #{$i/$n}, the attitude is controlled with the --a CSS variable that we animate from 0deg to 360deg to kill a plump rotation.
Right here’s where we would obtain caught with out a cramped extra mosey of contemporary CSS magic. Historically, CSS is unable to interpolate between CSS variables. That’s modified with the introduction of @property. It enables us to register a custom-made property and make clear its traits and, extra precisely, its sort (the employ of syntax) so as that the browser is conscious of tips on how to interpolate its values. It’s be pleased writing our non-public cramped CSS specification.
@property --a {
syntax: "";
initial-value: 0deg;
inherits: false;
}
Voilà! We have rotation.
Understand the Pen [Rotating the flower shape](https://codepen.io/t_afif/pen/oNQKgGX) by Temani Afif.
Now, let’s strive to management the rotation on streak. What about slowing it down on streak? Or speeding it up? Again, this is already doable in CSS, however even better with a most up-to-date technique that doesn’t require extra markup. And where shall we need crucial to make clear a pair of @keyframes, we now most efficient need one.
.box {
--d: 5s; /* Animation duration */
--s: 0.5; /* Speed factor
0: no change in speed
[0 1]: decreases the speed
1: stops the animation
[1 +infinity]: moves in the opposite direction */
--_a: r linear infinite;
animation:
var(--_a) var(--d),
var(--_a) calc(var(--d) / var(--s)) reverse paused;
animation-composition: add;
}
.box:hover {
animation-play-state: running;
}
@keyframes r {
to { rotate: 1turn }
}
The entire trick depends on the animation-composition property. Quoting MDN:
“The
animation-compositionCSS property specifies the composite operation to make employ of when a pair of animations non-public an mark on the identical property simultaneously.”
Quoting over again, this time relating to the add ticket:
add
The fabricate ticket builds on the underlying ticket of the property. This operation produces an additive fabricate.
I am applying the identical animation (named r for rotation) twice on the image, and by the employ of animation-compositon: add, both animations are combined. Understand how the 2nd animation runs in reverse and is paused. This form we originally ran the main animation. Then, on streak, both animations sail simultaneously.
And here comes the magic.
The result depends upon the length of the animations. If both animations sail at the identical length, the part stops altogether. The sort we’ve implemented the animations is that one moves forward and totally different in reverse, ensuing in no circulate the least bit. Yes, there’s a cramped physics to all of this.
Now, if the 2nd animation is slower (i.e., has the next length ticket) than the main, the initial rotation slows down. But if the 2nd animation is faster (i.e., has a smaller length ticket) than the main, the part rotates within the reverse direction.
This may per chance occasionally per chance presumably also fair sound a cramped confusing, however whenever you play with the code, it turns into plenty more straightforward to trace, particularly whenever you happen to’re a visual learner. Right here is a demo where that that you just can regulate totally different variables to play with the outcomes:
Understand the Pen [Hover to slow down the animation](https://codepen.io/t_afif/pen/vYQNLoe) by Temani Afif.
Let’s observe this to our instance and slack down the rotation on streak:
Understand the Pen [CSS-only Flower mask with rotation and hover effect](https://codepen.io/t_afif/pen/XWyGWyJ) by Temani Afif.
That’s awesome! Essentially the most efficient added bit in this situation is a scale fabricate to the smaller circle on streak. So, on streak, the smaller circles trade dimension as effectively as to the rotation slowing down.
We’ve been focusing on the physique as much as this point, however let’s re-introduce the avatar from the distinctive demo and work on making it “pop” out of the physique on streak.
Unfortunately, we are unable to merely re-scheme the identical hide we created for the physique. If we did, this is the end result:
Understand the Pen [Apply the mask to the avatar image](https://codepen.io/t_afif/pen/WNLejBB) by Temani Afif.
We have to guarantee that the hide doesn’t cloak the head of the avatar; otherwise, the hide sits on top of it. Let’s add another hide layer to the head piece of the physique with out obscuring the backside half of of the flower form.
img {
/* Same Sass loop, variables, etc. */
mask:
linear-gradient(#000 0 0) top / 100% 50% no-repeat, /* the new mask layer */
radial-gradient(#000 calc(72% - var(--r)/2), #0000 0),
$m;
We’re the employ of a linear gradient this time since that’s adequate for covering the head half of of the image part’s physique:
Understand the Pen [Removing the top portion of the mask](https://codepen.io/t_afif/pen/xxmKrKd) by Temani Afif.
We’re getting closer, however now not yet completed! The flower-shaped hide is most efficient the backside piece, however now we are lacking the head half of. We’re unable to obtain to the backside of this with mask this time, however we are able to create it the employ of the right background property since the background is painted within the support of the image relatively than in front of it.
No must dread! There are no complex math operations here. We defined gradients for the mask to kill the flower form, and we are able to reuse them on the background property to obtain the identical flower form, most efficient applied to the background of the image relatively than in front of it.
img {
/* etc */
mask:
linear-gradient(#000 0 0) top / 100% 50% no-repeat,
radial-gradient(#000 calc(72% - var(--r)/2), #0000 0),
$m;
background:
radial-gradient(#000 calc(72% - var(--r)/2), #0000 0),
$m;
}
All I did was copy mask’s radial gradient configuration and observe it to the background property. This supplies us the lacking fragment of our flower form.
Understand the Pen [Adding the background configuration](https://codepen.io/t_afif/pen/YzdKQXL) by Temani Afif.
The dim you witness within the background comes from the dim outdated school within the gradients. So, whenever you happen to desire a definite color, it ought to be updated by changing those values with another color ticket. The alpha channel is on the total the finest thing that matters when the employ of a mask, so altering dim to any totally different color gained’t manufacture a incompatibility in this context.
All that’s left to create is add the “pop out” fabricate on streak. For this, we are going first to interchange the gradient configuration, as illustrated within the next figure:

We’re on the total lowering the gap of the cramped circles, making them closer to the heart. Then, we slice again the scale of the simpler circle as effectively. This produces an fabricate that looks to trade the roundness of the smaller circles on streak.
The final trick is to scale your total image part to guarantee that the scale of the hovered form is the identical because the non-hovered form. Scaling the image manner that the avatar will obtain greater and can fair pop out from the physique that we made smaller.

$n: 15; /* number of circles */
@property --i {
syntax: "";
initial-value: 0px;
inherits: true;
}
img {
/* CSS variables */
--r: 50px; /* controls the small circle radius and initial size */
--f: 1.7; /* controls the scale factor */
--c: #E4844A; /* controls the main color */
$m: ();
/* Sass loop */
@for $i from 1 through ($n) {
$m: append($m,
radial-gradient(var(--c) 70%, #0000 72%) no-repeat
calc(50% + (50% - var(--i, 0px)) * cos(360deg * #{$i/$n} + var(--a, 0deg)))
calc(50% + (50% - var(--i, 0px)) * sin(360deg * #{$i/$n} + var(--a, 0deg))) /
var(--r) var(--r),
comma);
}
mask:
linear-gradient(#000 0 0) top/100% 50% no-repeat,
radial-gradient(var(--c) calc(72% - var(--r)/2 - var(--i, 0px)), #0000 0),
$m;
background:
radial-gradient(var(--c) calc(72% - var(--r)/2 - var(--i, 0px)), #0000 0),
$m;
transition: --i .4s, scale .4s;
}
img:hover {
--i: calc(var(--r)/var(--f));
scale: calc((1 + 1/sin(180deg/#{$n}))/(1 - 2/var(--f) + 1/sin(180deg/#{$n})));
}
Right here’s what’s modified:
- The Sass loop that defines the world of the circle makes employ of an equation of
50% - var(--i, 0px)as a replacement of a ticket of50%. - The upper circle makes employ of the identical variable,
--i, to area the color end of the main color within the gradients that are applied to themaskandbackgroundproperties. - The
--ivariable is updated from0pxto a obvious ticket. This form, the cramped circles switch area while the fat circle turns into smaller in dimension. - The
--ivariable is registered as a custom-made@propertythat allows us to interpolate its values on streak.
You furthermore may per chance can fair non-public noticed that I didn’t explain one thing else relating to the --f variable that’s defined on the image part. Honestly, there may per chance be now not any particular common sense to it. I will non-public defined any obvious ticket for the variable --i on streak, however I wished a ticket that depends upon --r, so I came up with a formula (var(--r) / var(--f)), where --f enables controls the scale.
Does the equation on the scale property on streak provide you with a cramped bit of alarm? It sure looks to be like complex, however I promise you it’s now not. We divide the scale of the initial form (which also will more than likely be the scale of the part) by the scale of the contemporary form to obtain the scale part.
- The initial dimension:
calc(var(--r)*(1 + 1 / sin(180deg / #{$n}))) - The dimensions of the contemporary form:
calc(var(--r) * (1 + 1 / sin(180deg / #{$n})) - 2 * var(--r) / var(--f))
I am skipping slightly diverse math crucial factors to now not manufacture the article lengthy, however feel free to comment on the article in picture for you additional part on the formulas I am the employ of.
That’s all! We have a very good “pop out” fabricate on streak:
Understand the Pen [Fancy Pop Out hover effect!](https://codepen.io/t_afif/pen/qBQzrwq) by Temani Afif.
Wrapping Up
Does all of this seem a cramped great? I witness that and know this is plenty to throw at somebody in a single article. We’re working with some elegant contemporary CSS factors, so there’s positively a discovering out curve with contemporary syntaxes, now not to explain some brushing up on math capabilities you per chance haven’t considered in years.
But we learned slightly diverse stuff! We outdated school gradients with some math to kill a fancy form that we applied as a hide and background. We launched @property to animate CSS variables and lift our form to existence. We also learned a very good trick the employ of animation-composition to management the rate of the rotation.
We soundless non-public a 2nd fragment of this article where we are able to reuse the identical CSS tactics to kill a fancier streak fabricate.
I’ll leave you with one remaining demo as a mark-off.
Understand the Pen [Pop out hover effect featuring Lea and Una](https://codepen.io/t_afif/pen/OJrLgeV) by Temani Afif.
(gg, yk)