A Starburst Variation On The Pop-Out Effect

In the previous article, we built a pop-out hover effect using a floral frame drawn entirely with CSS masks and trigonometric functions. The same toolkit can produce a starburst frame, and working through that variation is a useful way to see how the pieces fit together in a different geometry.

The core requirements are unchanged: the effect must work on a single <img> element, the frame must be drawn with gradients, and the avatar needs to overflow the top of the frame on hover. The starburst shape, however, pushes the masking technique further because it relies on mask-composite to cut triangular notches out of a circle.

Defining The Starburst Parameters

The starburst shape is controlled by three variables:

  • N: the number of spikes.
  • R: the radius of the outer circle.
  • p: a value in [0 1] that defines how deep the notches go, so the inner radius is R - (R * p).

Visually, the shape is a circle with triangular cutouts distributed around its perimeter. Instead of drawing the final shape directly, we construct it by starting with a circle and then removing triangles from it. The circles and triangles are created with a combination of conic-gradient and mask-composite. Getting the base circle is simple with border-radius: 50%, and the notch triangless are generated with conic gradients that are placed and rotated around the center.

Computing The Gradient Positions

Each notch is a conic gradient, and the number of gradients matches N. All of the gradients use essentially the same configuration; they differ only in their rotation. The position of each gradient is determined by a formula that is very close to the one from the floral effect in the previous article:

position = 50% + (50% - R) * cos(angle) + R * cos(angle)

Since R is 50%, this simplifies to a friendlier expression. The angle value comes out of the geometry of the starburst; deriving it involves some trigonometry that we won't fully walk through. Instead, we rely on the outcome and focus on how the gradients are compiled.

Because there is a repeating pattern, we stop writing plain CSS and use Sass loops to generate the gradient list. The following snippet assumes an <img> as the only element in the HTML and produces a starburst based on $n: 9 notches:

$n: 9;  /* number of spikes */

img {  
  --r: 160px; /* radius */
  --p: 0.25;  /* percent */ 
  --angle: atan(sin(180deg/#{$n}) / (var(--p) - 1 + cos(180deg/#{$n})));
  
  width: calc(2 * var(--r));
  aspect-ratio: 1;
  border-radius: 50%;
  $m: ();
  @for $i from 0 through ($n - 1) {
    $m: append($m, 
    conic-gradient(
     from calc(90deg + 360deg * #{$i/$n} - var(--angle)) at  
       calc(50% + (50% * (1 - var(--p))) v cos(360deg * #{$i/$n}))
       calc(50% + (50% * (1 - var(--p))) * sin(360deg * #{$i/$n})),
      #000 calc(2*var(--angle)), #0000 0),
      comma
    );
   }
  mask: $m;
}

That generates the raw starburst with the desired number of points. The output of the Sass loop is a variable that plugs directly into the mask property:

See the Pen [Starburst shape using CSS maks](https://codepen.io/t_afif/pen/KKbaLKQ) by Temani Afif.

See the Pen Starburst shape using CSS maks by Temani Afif.

At this point, the mask is hiding the starburst area, leaving only the spaces between the notches. We actually want the opposite: the starburst should be opaque, and everything outside it should be transparent. To invert the shape, we exclude the conic gradients from a linear gradient that covers the full mask area. Because the default composition for mask layers is add, and exclude is only needed on the final layer, we can apply it through the shorthand:

mask: 
 linear-gradient(#000 0 0), 
 $m; 
mask-composite: exclude, add, add, [...], add;

There is no intersection between the conic gradients in this static configuration, so the exclude keyword works cleanly. That result is the proper, opaque starburst frame:

See the Pen [Startburst shape using CSS Mask](https://codepen.io/t_afif/pen/XWopwRQ) by Temani Afif.

See the Pen Startburst shape using CSS Mask by Temani Afif.

Handling The Avatar Overflow

The hover effect requires the avatar to appear to pop out of the top half of the frame. That means the mask we built must be limited to the bottom half of the element, which we achieve by adding a linear gradient that covers the top half:

mask: 
  linear-gradient(#000 0 0) top/100% 50% no-repeat,
  linear-gradient(#000 0 0) exclude, 
  $m;

With the bottom half of the starburst masked, we reconstruct the top half using the background property. We can't use mask-composite in background, so we simulate the exclusion behavior with color. The same conic gradients are applied to the background, but they are filled with a color that matches the page behind the avatar. This keeps the visual result intact, even though it is not truly transparent.

See the Pen [Adding the background configuration](https://codepen.io/t_afif/pen/poqevbN) by Temani Afif.

See the Pen Adding the background configuration by Temani Afif.

Animating On Hover

The animation states require the starburst to shrink slightly while the avatar scales up. To reduce the size of the star, we adjust the position of the conic gradients, pulling them toward the center. The position formula gains an --i variable, which shifts the notches inward when it is set to a positive value:

calc(50% + (50%*(1 - var(--p)) - var(--i)) * cos(360deg * #{$i/$n} + var(--a)))
calc(50% + (50%*(1 - var(--p)) - var(--i)) * sin(360deg * #{$i/$n} + var(--a)))

On hover, --i becomes positive, which pulls the gradients inward, creating the smaller star. A similar adjustment is applied to the background property in the hover state. Because the gradients now overlap, it is essential that each conic gradient has an add composition with the others for both the mask and the background.

The image itself gets a scale transform on hover:

img {
  --f: 1.2; /* the scale factor */
  /* etc */
}
img:hover {
  scale: var(--f);
}

To prevent the two states from looking misaligned, the value of --i must relate to the scale factor. With a scale of 1.2, the offset is determined by the geometry of the notches, not by an arbitrary number:

img {
  --f: 1.2; /* the scale factor */
  /* etc */
}
img:hover {
  --i: calc(var(--r) * (1 - var(--p)) * (var(--f) - 1) / var(--f));
  scale: var(--f);
}

The final effect brings everything together:

See the Pen [Fancy Pop Out hover effect!](https://codepen.io/t_afif/pen/mdawrLa) by Temani Afif.

See the Pen Fancy Pop Out hover effect! by Temani Afif.

Sliding Into Place

The same code structure can produce another variant. Instead of the avatar being visible at rest, it is hidden and then slides up from behind the starburst as it grows on hover:

See the Pen [Fancy Pop Out Reveal hover effect!](https://codepen.io/t_afif/pen/VwqWRyj) by Temani Afif.

See the Pen Fancy Pop Out Reveal hover effect! by Temani Afif.

The sliding motion comes from the same pop-out mechanics used in the first demo, but only the positioning of the image is changed at the start of the transition. Studying how the existing code is adjusted to produce this behavior is a useful exercise for understanding how the mask, background, and scale interact.

A Closer Look at the Techniques

This second part moves at a quicker pace, but that is intentional. With the fundamentals from the earlier piece established, the focus here is on applying those same ideas in a fresh context. That means more attention goes to showing how masks and background gradients can be combined than to re-explaining each building block. The result is a tighter demonstration of how flexible modern CSS can be when you treat gradients as modular tools rather than static fills.

The value of this exercise is not in memorizing the exact formulas or the precise cascade of properties. It is in seeing how far you can push the boundaries without adding extra HTML or falling back on JavaScript. The math may look dense, but it exists to serve a wider point: you can keep a project highly maintainable by relying on a few custom properties and calc(). Adjust a single variable, and the entire effect recomputes. Without trigonometric functions and calc(), updating the design by hand would require touching many separate values, which is both tedious and error-prone.

There is no pressure to absorb all of it immediately. These are layered techniques, and it is perfectly reasonable to work through them step by step, revisiting whichever concept proves hardest to grasp. Honestly, you may never have a real project that demands all of these tricks at once. This is a deliberate, narrow use case—but that narrowness is exactly what makes it a useful sandbox. It isolates the tricks so you can study them individually and then carry them forward into more practical, everyday CSS challenges.

To finish, here is one more working demo that folds together everything we have touched on.

See the Pen [Pop out hover effect featuring Kevin and Alvaro](https://codepen.io/t_afif/pen/zYyWGPY) by Temani Afif.

See the Pen Pop out hover effect featuring Kevin and Alvaro by Temani Afif.
Smashing Editorial