Search code examples
htmlcssbordercss-shapes

Beveled corner on a rounded button


I need to create a rounded button with an information badge like this one :

enter image description here

How can I make the beveled corner on the green button around the red information badge ?

I cannot use a normal white border around the red badge (like in the below snippet), because it must be transparent and displays the page background color.

.shape {
  position: relative;
  height: 50px;
  width: 50px;
  border-radius: 50%;
  background: rgb(0, 199, 158);
  margin: 25px;
}
.shape:after {
  position: absolute;
  content: '';
  top: -10px;
  right: -10px;
  height: 25px;
  width: 25px;
  border-radius: 50%;
  border: 3px solid white;
  background: rgb(255, 67, 0);
}
body {
  background: chocolate;
}
<div class='shape'></div>


Solution

  • Using Box Shadow:

    One approach would be to use box-shadow on a pseudo-element like in the below snippet. Here, one pseudo-element (.shape:before) is positioned in such a way that it is a bit above the top-right corner of the circle and then its box shadow is used to fill the parent (.container) with required background color. The badge is added via another pseudo-element on the .container element.

    This has better browser support than the radial-gradient approach as it works in IE8+. Drawbacks would be that it can only support a solid background color for the main circle as shadows cannot be a gradient or an image. Also, it seems to require two elements (I am trying to reduce it and if successful will add it into answer).

    .container {
      position: relative;
      height: 50px;
      width: 50px;
      border-radius: 50%;
      margin: 25px;
    }
    .shape {
      position: absolute;
      height: 100%;
      width: 100%;
      top: 0px;
      left: 0px;
      border-radius: 50%;
      overflow: hidden;
    }
    .shape:before {
      position: absolute;
      content: '';
      height: 60%;
      width: 60%;
      top: -20%;
      right: -20%;
      border-radius: 50%;
      box-shadow: 0px 0px 0px 50px rgb(0, 199, 158);
    }
    .container:after {
      position: absolute;
      content: '2';
      height: 50%;
      width: 50%;
      right: -20%;
      top: -20%;
      background: rgb(255, 67, 0);
      color: white;
      line-height: 25px;
      text-align: center;
      border-radius: 50%;
    }
    
    /* just for demo */
    
    *, *:after, *:before {
      transition: all 2s;
    }
    .container:hover {
      height: 100px;
      width: 100px;
    }
    .container:hover .shape:before {
      box-shadow: 0px 0px 0px 100px rgb(0, 199, 158);  
    }
    .container:hover:after {
      line-height: 50px;
    }
    body {
      background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
      min-height: 100vh;
    }
    <div class='container'>
      <div class='shape'></div>
    </div>


    Using Radial Gradient:

    Another option would be to use radial-gradient for background-image like in the below snippet and position the background such that it produces a beveled corner on the top right. Once its done, adding the badge circle and positioning it should be fairly straight-forward.

    This has poorer browser support compared to the box-shadow approach as it works only in IE10+. If responsiveness is required then using gradients would be a better option as they can take percentage values unlike box shadows.

    .shape {
      position: relative;
      height: 50px;
      width: 50px;
      border-radius: 50%;
      background-image: radial-gradient(60% 60% at 92.5% 7.5%, transparent 49.5%, rgb(0,199,158) 50.5%);
      margin: 25px;
    }
    .shape:after {
      position: absolute;
      content: '2';
      height: 50%;
      width: 50%;
      right: -20%;
      top: -20%;
      background: rgb(255,67,0);
      color: white;
      line-height: 25px;
      text-align: center;
      border-radius: 50%;
    }
    
    /* just for demo */
    
    *, *:after {
      transition: all 1s;
    }
    .shape:hover {
      height: 100px;
      width: 100px;
    }
    .shape:hover:after {
      line-height: 50px;
    }
    body {
      background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
    }
    <div class='shape'></div>


    Using SVG:

    Another possibility would be to make use of SVG to create the beveled circle like in the below snippet.

    .shape {
      position: relative;
      height: 50px;
      width: 50px;
      border-radius: 50%;
      margin: 25px;
    }
    svg {
      position: absolute;
      height: 100%;
      width: 100%;
    }
    svg path {
      fill: rgb(0, 199, 158);
    }
    .shape:after {
      position: absolute;
      content: '2';
      height: 50%;
      width: 50%;
      right: -25%;
      top: -5%;
      background: rgb(255, 67, 0);
      color: white;
      line-height: 25px;
      text-align: center;
      border-radius: 50%;
    }
    
    /* just for demo */
    
    *, *:after {
      transition: all 2s;
    }
    .shape:hover {
      height: 100px;
      width: 100px;
    }
    .shape:hover:after {
      line-height: 50px;
    }
    body {
      background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
    }
    <div class='shape'>
      <svg viewBox='0 0 60 60'>
        <path d='M55,30 A25,25 0 0,1 5,30 A25,25 0 0,1 42.5,8.34 A16,16 0 0,0 55,30' />
      </svg>
    </div>

    Note: I've used pseudo-element for the badge just for illustration but since you'd need to add dynamic content into it, I'd recommend replacing that with a child element.