Search code examples
csssasscss-transformscss-shapes

How to create a lollipop shape by stacking divs in a circular manner?


How to stack divs in a circular manner in which last div should come beneath the first div but above the second last div. Is it possible with the css? any helps would be appreciated.

enter image description here

Please find the Codepen. Giving the sample code snippet

<div class="frame">
  <div class="lolly-pop__wrapper">
    <div class="lollypop-top">
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
    </div>
  </div>
</div>


.frame {
  position: absolute;
  display: flex;
  justify-content: center;
  top: 50%;
  left: 50%;
  width: 400px;
  height: 400px;
  margin-top: -200px;
  margin-left: -200px;
  border-radius: 2px;
  box-shadow: 4px 8px 16px 0 rgba(0,0,0,0.1);
  overflow: hidden;
  background: #F5CE51;
  color: #333;
  font-family: 'Open Sans', Helvetica, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.lollypop-top {
    position: relative;
    height: 150px;
    width: 150px;
    background-color: #fff;
    border-radius: 100%;
    overflow: hidden;

    .lollypop-top__item {
        position: absolute;
        height: 150px;
        width: 150px;
        top: -50%;
        border-radius: 100%;
        transform-origin: bottom;
        background-color: #fff;

        &:nth-child(odd) {
            background-color: #D70606;
        }

        &:nth-child(1) {
            transform: rotate(30deg);
        }

        &:nth-child(2) {
            transform: rotate(60deg);
        }

        &:nth-child(3) {
            transform: rotate(90deg);
        }

        &:nth-child(4) {
            transform: rotate(120deg);
        }

        &:nth-child(5) {
            transform: rotate(150deg);
        }

        &:nth-child(6) {
            transform: rotate(180deg);
        }

        &:nth-child(7) {
            transform: rotate(210deg);
        }

        &:nth-child(8) {
            transform: rotate(240deg);
        }

        &:nth-child(9) {
            transform: rotate(270deg);
        }

        &:nth-child(10) {
            transform: rotate(300deg);
        }

        &:nth-child(11) {
            transform: rotate(330deg);
        }

        &:nth-child(12) {
            transform: rotate(360deg);
        }
      }
    }

.frame {
  position: absolute;
  display: flex;
  justify-content: center;
  top: 50%;
  left: 50%;
  width: 400px;
  height: 400px;
  margin-top: -200px;
  margin-left: -200px;
  border-radius: 2px;
  box-shadow: 4px 8px 16px 0 rgba(0, 0, 0, 0.1);
  overflow: hidden;
  background: #F5CE51;
  color: #333;
  font-family: 'Open Sans', Helvetica, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.lollypop-top {
  position: relative;
  height: 150px;
  width: 150px;
  background-color: #fff;
  border-radius: 100%;
  overflow: hidden;
}

.lollypop-top .lollypop-top__item {
  position: absolute;
  height: 150px;
  width: 150px;
  top: -50%;
  border-radius: 100%;
  transform-origin: bottom;
  background-color: #fff;
}

.lollypop-top .lollypop-top__item:nth-child(odd) {
  background-color: #D70606;
}

.lollypop-top .lollypop-top__item:nth-child(1) {
  transform: rotate(30deg);
}

.lollypop-top .lollypop-top__item:nth-child(2) {
  transform: rotate(60deg);
}

.lollypop-top .lollypop-top__item:nth-child(3) {
  transform: rotate(90deg);
}

.lollypop-top .lollypop-top__item:nth-child(4) {
  transform: rotate(120deg);
}

.lollypop-top .lollypop-top__item:nth-child(5) {
  transform: rotate(150deg);
}

.lollypop-top .lollypop-top__item:nth-child(6) {
  transform: rotate(180deg);
}

.lollypop-top .lollypop-top__item:nth-child(7) {
  transform: rotate(210deg);
}

.lollypop-top .lollypop-top__item:nth-child(8) {
  transform: rotate(240deg);
}

.lollypop-top .lollypop-top__item:nth-child(9) {
  transform: rotate(270deg);
}

.lollypop-top .lollypop-top__item:nth-child(10) {
  transform: rotate(300deg);
}

.lollypop-top .lollypop-top__item:nth-child(11) {
  transform: rotate(330deg);
}

.lollypop-top .lollypop-top__item:nth-child(12) {
  transform: rotate(360deg);
}
<div class="frame">
  <div class="lolly-pop__wrapper">
    <div class="lollypop-top">
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
      <div class="lollypop-top__item"></div>
    </div>
  </div>
</div>


Solution

  • I would create this considering two elements (pseudo elements) and multiple radial gradient. You only need to create half the shape twice and rotate one of them.

    .box {
      width:150px;
      height:150px;
      border-radius:100%;
      border:1px solid;
      position:relative;
      overflow:hidden;
    }
    .box::before,
    .box::after{
      content:"";
      position:absolute;
      top:0;
      bottom:0;
      left:0;
      right:50%;
      background:
        /*we rotate by 30deg so will use :
           sin(30deg)*R = 0.5x75px   = 37.5px 
           cos(30deg)*R = 0.866x75px = 64.95px       
           10.05px = 75px - 64.95px;
           112.5px = 75px + 37.5px
           139.95px = 75px + 64.95px
           37.5px = 75px - 37.5px
           */
        radial-gradient(circle 75px at 139.95px 37.5px,red   98%,transparent 100%),
        radial-gradient(circle 75px at 112.5px 10.05px,white 98%,transparent 100%),
        radial-gradient(circle 75px at 75px    0,      red   98%,transparent 100%),
        radial-gradient(circle 75px at 37.5px  10.05px,white 98%,transparent 100%),
        radial-gradient(circle 75px at 10.05px 37.5px ,red   98%,transparent 100%),
        radial-gradient(circle 75px at 0       75px,   white 98%,transparent 100%),
        radial-gradient(circle 75px at 10.05px 112.5px,red   98%,transparent 100%);
    }
    
    .box::after {
     transform:rotate(180deg);
     transform-origin:right;
    }
    <div class="box">
    
    </div>

    CSS lollipop shape

    To make things more funny we can add CSS variables to easily control the shape:

    .box {
      --R:50px; /*Radius*/
      --c1:red; /*first color*/
      --c2:#fff; /*second color*/
      
      --g1:var(--c1) 98%, transparent 100%;
      --g2:var(--c2) 98%, transparent 100%;
      width:calc(2*var(--R));
      height:calc(2*var(--R));
      border-radius:100%;
      border:1px solid;
      position:relative;
      overflow:hidden;
      display:inline-block;
      vertical-align:middle;
    }
    .box::before,
    .box::after{
      content:"";
      position:absolute;
      top:0;
      bottom:0;
      left:0;
      right:50%;
      background:
         /*we rotate by 30deg so will use :
           sin(30deg)*R = 0.5xR   
           cos(30deg)*R = 0.866xR 
         */
        radial-gradient(circle var(--R) at calc(var(--R) + 0.866*var(--R)) calc(var(--R) - 0.5*var(--R))  ,var(--g1)),
        radial-gradient(circle var(--R) at calc(var(--R) + 0.5*var(--R))   calc(var(--R) - 0.866*var(--R)),var(--g2)),
        radial-gradient(circle var(--R) at var(--R)                        0                              ,var(--g1)),
        radial-gradient(circle var(--R) at calc(var(--R) - 0.5*var(--R))   calc(var(--R) - 0.866*var(--R)),var(--g2)),
        radial-gradient(circle var(--R) at calc(var(--R) - 0.866*var(--R)) calc(var(--R) - 0.5*var(--R))  ,var(--g1)),
        radial-gradient(circle var(--R) at 0                               var(--R)                        ,var(--g2)),
        radial-gradient(circle var(--R) at calc(var(--R) - 0.866*var(--R)) calc(var(--R) + 0.5*var(--R))  ,var(--g1));
    }
    
    /*the same shape rotated*/
    .box::after {
     transform:rotate(180deg);
     transform-origin:right;
    }
    <div class="box"></div>
    
    <div class="box" style="--R:80px;--c1:blue"></div>
    
    <div class="box" style="--R:100px;--c1:green;--c2:yellow"></div>
    
    <div class="box" style="--R:150px;--c1:white;--c2:pink"></div>


    Note that Safari doesn't support the syntax with at (explained here How to make radial gradients work in Safari?) so here is anothe syntax:

    .box {
      --R:50px;  /*Radius*/
      --c1:red;  /*first color*/
      --c2:#fff; /*second color*/
      
      width:calc(2*var(--R));
      height:calc(2*var(--R));
      border-radius:100%;
      border:1px solid;
      position:relative;
      overflow:hidden;
      display:inline-block;
      vertical-align:middle;
    }
    .box::before,
    .box::after{
      content:"";
      position:absolute;
      inset: 0 50% 0 0;
      --g1:radial-gradient(50% 50%,var(--c1) 98%, #0000);
      --g2:radial-gradient(50% 50%,var(--c2) 98%, #0000);
      background:
         /*we rotate by 30deg so will use :
           sin(30deg)*R = 0.5xR   
           cos(30deg)*R = 0.866xR 
         */
        var(--g1) calc(0.866*var(--R)) calc(var(--R)/-2), 
        var(--g2) calc(var(--R)/2) calc(-0.866*var(--R)),
        var(--g1) 0 calc(-1*var(--R)),
        var(--g2) calc(var(--R)/-2) calc(-0.866*var(--R)),
        var(--g1) calc(-0.866*var(--R)) calc(var(--R)/-2),
        var(--g2) calc(-1*var(--R)) 0,
        var(--g1) calc(-0.866*var(--R)) calc(var(--R)/2);
       background-size:calc(2*var(--R)) calc(2*var(--R));
       background-repeat:no-repeat;
    }
    
    /*the same shape rotated*/
    .box::after {
     transform:rotate(180deg);
     transform-origin:right center;
    }
    <div class="box"></div>
    
    <div class="box" style="--R:80px;--c1:blue"></div>
    
    <div class="box" style="--R:100px;--c1:green;--c2:yellow"></div>
    
    <div class="box" style="--R:150px;--c1:white;--c2:pink"></div>

    multicolor lollipop shape CSS

    Here is a Codepen demo to play with the code