DEV Community

Cover image for Fancy Clipping with CSS
Alvaro Montoro
Alvaro Montoro Subscriber

Posted on • Originally published at alvaromontoro.com

Fancy Clipping with CSS

I have been using clip-path for ages, especially for CSS Art, but I was today years old when I learned some of the features that are available for the polygon() function in clip-path.


The other day, Temani Afif shared a demo that included some weird (to me) syntax for the polygon() function that allowed creating rounded shapes. It included the keyword round and a length. Something like this:

clip-path: polygon(round 10px, 100% 55%, 0 71%, 71% 0, 55% 100%, 10% 10%);
Enter fullscreen mode Exit fullscreen mode

I have always used polygon() specifying a series of points that were used to clip the element that ended with really sharp edges. So, the first thing I thought was "This must be some Chrome-only experiment or something." And I was partially correct. Yes, it only works on Chrome at the moment, but the rounded behavior is defined in the CSS specification.

If you have code that specifies roundness in the polygon, for example:

div {
  width: 300px;
  height: 300px;
  background: red;
  clip-path: polygon(round 10px, 100% 55%, 0 71%, 71% 0, 55% 100%, 10% 10%);
}
Enter fullscreen mode Exit fullscreen mode

You will get a rounded figure with clip-path. For the code above, it would be this (only on Chrome):

A rounded star in Chrome using clip-path :)
 

I have to admit, for me this was a mind-blown type of moment. Getting rounded edges before this required masking with SVG, or coming up with relatively complex native CSS, including masks and gradients. (Although thee the shape() function makes this considerably easier now.)

This feature is amazing, especially for the CSS Art that I like coding, but there's a big issue.

Support and Progressive Enhancement

As I have mentioned a few times before, this rounded feature is in the specs but at the moment it is only supported by Chrome. So... what happens when it runs on other browsers like Firefox or Safari?

Unfortunately, the answer is not good: the function is considered invalid and it is completely ignored. Which means that not only do we not get a rounded polygon, we don't get a polygon at all!

The same rounded star on Safari and Firefox :(
 

In the future we could use the CSS @if and @function at rules to have a rounded-polygon() function that would do this for us, but for now we need to find an alternative to progressively enhance the feature or gracefully degrade if it is not supported.

But there is something that we can currently do: use the @supports at-rule combined with custom properties.

:root {
  --round-clip:;

  @supports (clip-path: polygon(round 1px, 0 0, 0 0)) {
    --round-clip: round 10px,; /* notice the comma! */
  }
}

div {
  ...
  clip-path: polygon(var(--round-clip) 100% 55%, 0 71%, 71% 0, 55% 100%, 10% 10%);
}
Enter fullscreen mode Exit fullscreen mode

Now, by default the variable will be empty, so we will get the "classic" clip-path with pointy edges. But, if rounded clipping is supported, the custom property will have a value that makes the clip-path have rounded edges:

Pointy star by default (left), and rounded star if supported (right) :D
 

I will not get into the weeds of how the roundness is calculated, but the CSS specification has a section with an explanation and many details on that.

But wait... there's more!

While the rounded paths are not supported by all browsers, there is another feature that I didn't know about and it is actually widely supported, even by Safari and Firefox: fill rules.

When you define a clip-path, all the area inside the path will be selected and visible, but developers can specify different keywords to have some control over that:

  • nonzero (default): the points inside the path will not be clipped.
  • evenodd: everything outside the path will be clipped, but within the path, it will depend on the count of lines and path edges around each point. If it's even, it will be clipped; if it's odd, it won't and it will be visible.

This is an oversimplification. The SVG specification has a more detailed explanation of how both keywords work, and I encourage you to read it.

Here's the example of the star from before using nonzero (default, could be omitted) and evenodd fill rules:

.div1 {
  ...
  clip-path: polygon(nonzero, 100% 55%, 0 71%, 71% 0, 55% 100%, 10% 10%);
}

.div2 {
  ...
  clip-path: polygon(evenodd, 100% 55%, 0 71%, 71% 0, 55% 100%, 10% 10%);
}
Enter fullscreen mode Exit fullscreen mode

nonzero clipping (left) vs evenodd clipping (right)
 

The nonzero and evenodd fill rules would go before the round keyword if we are applying rounded clip paths. No comma separating the two. For example:

div {
  ...
  clip-path: polygon(nonzero round 10px, 100% 55%, 0 71%, 71% 0);
}
Enter fullscreen mode Exit fullscreen mode

The fill-rules syntax not only works for polygon(). It also works with shape() and path(), so it's nice to get acquainted with it.


One of the fascinating things about CSS is how complete (and sometimes complex) it can be. You think you know about it and, boom! There's something different, and not necessarily new that you learn about it... even when you have used it continuously. You have to love that.

Here's an interactive demo that lets you play with the values described above: roundness, fill rules, and fallbacks (will only make a difference on Safari and Firefox). Tweak the controls and see how the star changes.

Top comments (0)