Как создать форму леденца на палочке, складывая блоки по кругу?

Как складывать div по кругу, при этом последний div должен располагаться ниже первого div, но выше второго последнего div. Возможно ли это с помощью CSS? Любая помощь будет оценена.

введите сюда описание изображения

Найдите Codepen. Предоставление образца фрагмента кода

<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>

Свободный перевод вопроса How to create a lollipop shape by stacking divs in a circular manner? от участника @Vivekraj K R.


Ответы (2 шт):

Автор решения: Alexandr_TT

Я бы создал это с учетом двух элементов (псевдоэлементов) и множественного радиального градиента. Вам нужно всего лишь дважды создать половину формы и повернуть одну из них.

.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, чтобы легко управлять формой:

.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>

Обратите внимание, что Safari не поддерживает синтаксис с at (объясняется здесь Как заставить радиальные градиенты работать в Safari?), Поэтому вот другой синтаксис:

.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(farthest-side,var(--g1)) calc(var(--R) + 0.866*var(--R) - var(--R)) calc(var(--R) - 0.5*var(--R) - var(--R)),
     
    radial-gradient(farthest-side,var(--g1)) calc(var(--R) + 0.866*var(--R) - var(--R)) calc(var(--R) - 0.5*var(--R) - var(--R)),
    radial-gradient(farthest-side,var(--g2)) calc(var(--R) + 0.5*var(--R) - var(--R))   calc(var(--R) - 0.866*var(--R) - var(--R)),
    radial-gradient(farthest-side,var(--g1)) 0 calc(-1*var(--R)),
    radial-gradient(farthest-side,var(--g2)) calc(var(--R) - 0.5*var(--R) - var(--R))   calc(var(--R) - 0.866*var(--R) - var(--R)),
    radial-gradient(farthest-side,var(--g1)) calc(var(--R) - 0.866*var(--R) - var(--R)) calc(var(--R) - 0.5*var(--R) - var(--R)),
    radial-gradient(farthest-side,var(--g2)) calc(-1*var(--R))  0,
    radial-gradient(farthest-side,var(--g1)) calc(var(--R) - 0.866*var(--R) - var(--R)) calc(var(--R) + 0.5*var(--R) - var(--R));
   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>

Свободный перевод ответа от участника @Temani Afif.

→ Ссылка
Автор решения: Alexandr_TT

Моим подходом был бы многоразовый SVG <symbol> с контурами, образованными кривыми квадратичного безье:

#svg-lollipop path { transform-origin: 50% 50%; }

#svg-lollipop path:nth-child(2) {  transform: rotateZ(60deg); }
#svg-lollipop path:nth-child(3) {  transform: rotateZ(120deg); }
#svg-lollipop path:nth-child(4) {  transform: rotateZ(180deg); }
#svg-lollipop path:nth-child(5) {  transform: rotateZ(240deg); }
#svg-lollipop path:nth-child(6) {  transform: rotateZ(300deg); }

.lollipop {
  width: 30%;
  display: inline-block;
  overflow: hidden;
  border-radius: 50%;
  position: relative;
  margin: 0 20px;
}

.lollipop::before {
  content: "";
  padding-bottom: 100%;
  display: block;
}

.lollipop svg {
  position: absolute;  
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  height: 100%;
  fill: currentColor;
}

.lollipop--animated {
  animation: rotate 10s linear 0s infinite;
}

@keyframes rotate {
  0% { transform: rotateZ(0) }
  100% { transform: rotateZ(1turn) }
}
<svg style="display: none;">
   <symbol id="svg-lollipop">
      <path d="M150,150 Q75,185 0,150 H0 V63.6 Q75,150 150,150 z" />
      <path d="M150,150 Q75,185 0,150 H0 V63.6 Q75,150 150,150 z" />
      <path d="M150,150 Q75,185 0,150 H0 V63.6 Q75,150 150,150 z" />
      <path d="M150,150 Q75,185 0,150 H0 V63.6 Q75,150 150,150 z" />
      <path d="M150,150 Q75,185 0,150 H0 V63.6 Q75,150 150,150 z" />
      <path d="M150,150 Q75,185 0,150 H0 V63.6 Q75,150 150,150 z" />
   </symbol>
</svg>

<div class="lollipop lollipop--animated" 
  style="background-color: #FFF; color:#E92120;">
  <svg viewBox="0 0 300 300"><use xlink:href="#svg-lollipop"></use></svg>
</div>

<div class="lollipop" 
  style="background-color: #004991; color:#007BC1;">
  <svg viewBox="0 0 300 300"><use xlink:href="#svg-lollipop"></use></svg>
</div>

Как это работает:

Та же форма была клонирована 6 раз и повернута, чтобы заполнить весь svg.
В этом примере каждая цветная фигура имеет угол α = 30 градусов.

Затем из тригонометрии мы можем найти координаты исходных точек для кривых: в пути координата y 63.6 получается как 150 - (150 * tan (α)), поэтому, если вам нужно изменить количество фигур и угол, вы можете легко найти исходные точки (квадратичные кривые действительно легко нарисовать).

Наконец, внешняя оболочка имеет border-radius и hidden overflow, чтобы придать округлую форму.

введите сюда описание изображения

Конечный результат также является отзывчивым, поскольку внешняя оболочка сохраняет соотношение сторон 1: 1.

Белая область может быть изменена с помощью background-color, установленного на контейнере, цветная область может быть изменена вместо этого с помощью свойства color (для вашего удобства свойство fill элементов svg установлено на currentColor).


кое-что я заметил позже:

если добавить box-shadow: inset 0 0 20px #aaa; для обертки изображение больше похоже на надувной воздушный шар на пляже, чем на леденец.

Свободный перевод ответа от участника @Fabrizio Calderan.

→ Ссылка