The case for crescent-shaped avatars 🌙
Tags: Front End Development, Clipping Path, Mask, Design Systems, CSS

Part of our work on Radiant — Thoughtspot’s design system — was to recreate our Avatar component, and more specifically its crescent shape when we need to display more than one at a time.

Our first intent was to set a white border to the round shape, which might look like this:

.avatar {

width: 32px;

height: 32px;

border-radius: 50%;

border: solid 1px white

}

As a side note, I often ask candidates to create a round-shaped element to see if they’ll use border-radius:50% , it gives me an indication on how much they know about CSS.

OK, so this works but what we’re really doing is faking it on white background. It doesn’t look so great on dark or color.

Clearly doesn’t look as intended.

So, instead of setting a border, we need to create a mask or clip on all except the last one in order to get the desired crescent shapes.

First try: using clip-path

The first idea that came to mind was to use clip-path with a circle shape and translate it to the right:

Yep, that’s the plan.

Unfortunately, this is not how clip-path works and there’s apparently no way to tell clip-path to clip what’s inside its path, not outside.

Yeah, that’s not what we want.

OK so that doesn’t work, what else can we try?

Second attempt: using clip-path with SVG

So we can’t use a simple CSS shape but clip-path also accepts SVGs as a path. Let’s create a more elaborated shape in S̵k̵e̵t̵c̵h̵ our preferred design tool then!

The white shape is our new path.

Before we go on, we need to keep in mind that clip-path is not universally supported — Hello IE and Edge! — so we need to have some progressive enhancement strategy, which you can see in the following pen:

Hey! That’s better!

This time, it works as expected but:

- you have to create an SVG (i.e. hard to impossible to do it programmatically)

- you have to have it in the page because external SVGs are not really supported yet — good job Firefox!

- you have to hide this SVG one way or another (i.e. probably hacky)

Can we do better?

Third attempt: Ask the Expert™ Edition

Let’s go back to what we stated earlier: you cannot specify a clip-path to cut the inner part of an element. That’s true but you can hack it:

Ana Tudor wrote this great article that uses polygons.

Great… but a polygon is not a circle you might say.

Except if you add a few more vertices.

And a few more.

A 50 vertices polygon.

So in theory you can create something like a clip-path with a very complicated polygon, but that seems over-engineered, no?!

Fourth attempt: let’s try with mask instead

The main difference between mask and clip-path is that mask is using an image to hide parts of the parent element: the image needs to have black (for transparent) and white (for opaque) parts to create the mask.

That’s great but how would that be better than creating an SVG if we have to create an external image to achieve our crescent shape?

But — as Ana Tudor hinted in her tweet — you can also use CSS gradients in a mask ! When you do, the transparent parts will be what’s hidden of the parent element.

And for our use case, we can use radial-gradient !

Hooray!

Let’s dive in the meatier part of the code:

mask: radial-gradient(circle at 41px, transparent 17px, white 0);

17px is the radius of the mask. Its calculation is half of our avatar component (32px / 2), plus 1px otherwise you won’t be able to see it with the following avatar on top of it (you can add more than 1px for a bolder effect).

41px it’s the 3/4th of our avatar element (32px * 3/4 = 24px) + the radius of the mask (17px)

Don’t forget to move the avatars — all but the first one — to the left by 1/4th of the avatar width (8px) minus the border that you chose (here 1px) to achieve the final result.

Now, that’s what I call a nice looking CSS-based crescent-shaped avatar! ✌️