<div class="wrapper wrapper--high">
  <!-- Spinning discs -->
  <div class="pie spinner-left"></div>
  <div class="pie spinner"></div>
  
  <!-- Visibility masks -->
  <div class="mask"></div>
  <div class="mask-right"></div>
  
  <!-- The content -->
  <div class="content">!</div>
</div>

<div class="wrapper wrapper--good">
  <!-- Spinning discs -->
  <div class="pie spinner-left"></div>
  <div class="pie spinner"></div>
  
  <!-- Visibility masks -->
  <div class="mask"></div>
  <div class="mask-right"></div>
  
  <!-- The content -->
  <div class="content">!</div>
</div>

<div class="wrapper wrapper--sat">
  <!-- Spinning discs -->
  <div class="pie spinner-left"></div>
  <div class="pie spinner"></div>
  
  <!-- Visibility masks -->
  <div class="mask"></div>
  <div class="mask-right"></div>
  
  <!-- The content -->
  <div class="content">!</div>
</div>

<div class="wrapper wrapper--low">
  <!-- Spinning discs -->
  <div class="pie spinner-left"></div>
  <div class="pie spinner"></div>
  
  <!-- Visibility masks -->
  <div class="mask"></div>
  <div class="mask-right"></div>
  
  <!-- The content -->
  <div class="content">!</div>
</div>
body {
  background-color: #CCC;
  text-align: center;
}

.wrapper {
  margin-left: 15%;
  margin-right: 15%;
  margin-bottom: 50px;
  top: 50px;
  position: relative;
  background-color: white;
  border-radius: 250px;
  -webkit-backface-visibility: hidden;
  display: inline-block;
}

@mixin engagement-badge($item, $duration, $size, $colour, $rotation) {
   
  $animation: true;
   
  // Animations are unqiue depending on the degrees the circle is filled so we need to uniquely prefix them.
  $prefix: unique-id() + '--';
  $spinA: null;
  $spinB: null;
  $time: null;
  $curveA: null;
  $curveB: null;
  $border-size: $size * 0.12;
  $arrow-size: $border-size / 2;
  
  @if $rotation > 180 {
    $spinA: 180deg;
    $spinB: $rotation + deg;
    $time: (180 / $rotation) * 100; 
    $curveA: ease-in;
    $curveB: ease-out;
  } @else {
    $spinA: ($rotation + deg);
    $spinB: 180deg;
    $time: 100;
    $curveA: ease-out;
    $curveB: linear;
  }
  
  #{$item}, #{$item} * { 
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
  }
  
  #{$item} { 
    width: $size;
    height: $size;
  }

  #{$item} .pie {
    width: 50%;
    height: 100%;
    transform-origin: 100% 50%;
    position: absolute;
    background: transparent;
    border: $border-size solid #{$colour};
    border-radius: $size;
  }

  #{$item} .spinner {
    border-radius: 100% 0 0 100% / 50% 0 0 50%;
    z-index: 200;
    border-right: none;
    @if $animation { animation: #{$prefix + rota} $duration + s $curveA 1; }
    transform: rotate($spinA);
    
  }
  
  #{$item} .spinner-left {
    border-radius: 100% 0 0 100% / 50% 0 0 50%;
    z-index: 190;
    border-right: none;
    @if $animation { animation: #{$prefix + rota-left} $duration + s $curveB 1; }
    transform: rotate($spinB);
  }

  #{$item} .mask {
    width: 50%;
    height: 100%;
    position: absolute;
    background: inherit;
    z-index: 300;
    border-top-left-radius: $size;
    border-bottom-left-radius: $size;
    
    @if $rotation >= 180 {
      opacity: 0;
      @if $animation { animation: #{$prefix + opa} $duration + s steps(1,end) 1; }
    } @else {
      opacity: 1;
    }
  }
  
  #{$item} .mask-right {
    width: 50%;
    height: 100%;
    position: absolute;
    background: inherit;
    opacity: 1;
    z-index: 195;
    right: 0;
    border-top-right-radius: $size;
    border-bottom-right-radius: $size;
  }
  
  @keyframes #{$prefix + rota} {
    0% { transform: rotate(0deg); }
    #{$time}% { transform: rotate($spinA); }
  }
  
  @keyframes #{$prefix + rota-left} {
    0% { transform: rotate(180deg); }
    #{$time}% { transform: rotate(180deg); }
    100% { transform: rotate($spinB); }
  }

  @keyframes #{$prefix + opa} {
    0% { opacity: 1; }
    #{$time}%, 99% { opacity: 0; }
  }
  
  @keyframes #{$prefix + fill-opa} {
    0% { opacity: 1; }
    50% { opacity: 0; }
  }
  
  /* MIDDLE CONTENT */
  
  @keyframes #{$prefix + pop} {
    0% {
      opacity: 0;
      transform: scale3d(0,0,0);
    }

    70% {
      transform: scale3d(1.4, 1.4, 1.4);
    }

    100% {
      transform: scale3d(1, 1, 1);
    }
    
  }
  
  #{$item} .content {
    background-color: darken($colour, 10%);
    width: ($size - ($border-size * 2)) + 2;
    height: ($size - ($border-size * 2)) + 2;
    z-index: 1001;
    position: absolute;
    border-radius: $size;
    font-size: ($size - ($border-size * 2));
    text-align: center;
    line-height: ($size - ($border-size * 2));
    color: darken($colour, 30%);
    margin: $border-size - 1;
    
    @if $animation { animation: #{$prefix + pop} $duration + s ease-in-out 1; }
  }
 
  /* ARROW */
  
  #{$item} .spinner::after,
  #{$item} .spinner-left::after {
    content: '';
    display: block;
    position: absolute;
    top: -$border-size;
    right: -$arrow-size + 1;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: $arrow-size 0 $arrow-size $arrow-size;
    border-color: transparent transparent transparent $colour;
    margin-left: 9px;
    transform: scale(.9999);
    z-index: 500;
    -webkit-backface-visibility: hidden;
    -webkit-transform: translateZ(0) scale(1.0, 1.0);
  }
}

$badge-size: 150px;
$speed: 1.3;

@include engagement-badge('.wrapper--high', $speed, $badge-size, #2FC37A, 360);

@include engagement-badge('.wrapper--good', $speed, $badge-size, #37C6E1, 270);

@include engagement-badge('.wrapper--sat', $speed, $badge-size, #BA79DA, 181);

@include engagement-badge('.wrapper--low', $speed, $badge-size, #C73160, 90);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.