Creating rounded triangles in CSS with clip-path

In this quick tutorial, we'll take a look at a practical example where the clip-path property can make your life easier. We're going to design a CSS triangle that inherits some properties from its parent.

A few days ago, we updated the Tooltip component and replaced the 'border hack' with the clip-path method to create CSS triangles (the small arrow appearing beside the tooltip).

In this specific case, using clip-path brought a few advantages. We're going to take a look at them, as well as a few other nifty CSS tricks.

👉 I'm aware the clip-path property is not supported in all browsers. However, it's currently supported in all major browsers (except Microsoft Edge), so it's OK to use it if what you're creating is an enhancement and it won't break user experience in older browsers.

Let's do this! #

I've put together a video tutorial that explains how to create a 'rounded' triangle with clip-path. Feel free to skip the video if you prefer to read the article.

Join us on our YouTube channel for more tutorials!

Probably the most popular approach to creating CSS triangles is the border hack:

If you set height and width of an element equal to 0, then apply a transparent border, if you then set only one border color (e.g., border-bottom-color) to any value you want, you end up with a triangle. It's a cool trick, and we also have a mixin in our framework that does exactly this:

// CSS triangle
@mixin triangle ($direction: up, $width: 12px, $color: red) {
  width: 0;
  height: 0;
  border: $width solid transparent;

  @if( $direction == left ) {
    border-right-color: $color;
  } @else if( $direction == right ) {
    border-left-color: $color;
  } @else if( $direction == down ) {
    border-top-color: $color;
  } @else {
    border-bottom-color: $color;
  }
}

However, this method has some limitations. If we consider the tooltip case, the triangle can't inherit the background color of the parent (you're forced to set a variable, or to update two values). Also, if you set a border on the parent, it's not easy to set a border on the triangle too (we're using the border property to create the triangle itself).

An alternative approach would be using inline SVG code. Smart, but not as simple as using a <div> or a pseudo-element.

One method I've been experimenting with and that seems cool consists of using the clip-path property:

The idea is simple: we turn a square into a triangle using the clip-path property. To do so, you need to pass to the polygon function three sets of coordinates:

  • 0% 0% 👉top left corner
  • 100% 100% 👉bottom right corner
  • 0% 100% 👉bottom left corner

Remember the first coordinate defines the position on the x-axis, while the second one on the y-axis.

clip-path coordinates
clip-path coordinates

What's the advantage of using clip-path? For starter, we can set both background-color and border values equal to inherit. Anytime you update the style of the tooltip, the triangle is updated as well. Secondly, you can set a border radius and make the triangle...well...rounded. I realize it's not something you plan on often doing. But still, it's a neat trick!

What about older browsers? We can use the @support rule to show the triangle only in browsers supporting clip-path. In those that don't, we hide the triangle.

.triangle {
  display: none;
}

@supports (clip-path: inset(50%)) {
  .triangle {
    display: block;
    height: 20px;
    width: 20px;
    background-color: inherit;
    border: inherit;
    position: absolute;
    bottom: -10px;
    left: calc(50% - 10px);
    clip-path: polygon(0% 0%, 100% 100%, 0% 100%);
    transform: rotate(-45deg);
    border-radius: 0 0 0 0.25em;
  }
}

Is it bad? Not in this case, where the tooltip works fine without the little arrow.

Done! 🎉

Feedbacks/suggestions? Get in touch on Twitter.