Zig zag border for a circle?

2019-03-18 07:58发布

问题:

Based on many tutorials I am able to create a zig zag border for square/rectangle objects using :after and :before. However when it comes to circles there are no tutorials at all.

I would like to create an object that looks like this:

Is that possible by using CSS only?

回答1:

I would consider using SVG with some rotation and use them as backgrounds.

Here is an attempt that can give you an idea about how it can be done. Basically, the SVG is the same and we simply repeat and rotate until we get the full shape. The main trick is to find the correct values:

Here is the final code:

.zigzag {
   width:256px;
   height:256px;
   background:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256'> <path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' /></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256' style='transform:rotate(16.36deg);'> <path  d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' /></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256' style='transform:rotate(32.73deg);'> <path  d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' /></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256' style='transform:rotate(49.09deg);'> <path  d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' /></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256' style='transform:rotate(65.45deg);'> <path  d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' /></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256' style='transform:rotate(81.81deg);'> <path  d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' /></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256' style='transform:rotate(98.18deg);'> <path  d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' /></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256' style='transform:rotate(114.54deg);'> <path  d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' /></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256' style='transform:rotate(130.90deg);'> <path  d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' /></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256' style='transform:rotate(147.27deg);'> <path  d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' /></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256' style='transform:rotate(164.2deg);'> <path  d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' /></svg>");
    background-size:100% 100%;
    
    font-size:28px;
    line-height:256px;
    color:#fff;
    text-align:center;
}

body {
 background:pink;
}
<div class="zigzag">
zig zag circle
</div>


You can also use it as a simple SVG. In this case, you can put all the paths inside the same SVG and apply rotation to them.

Here I used calc to calculate the value of rotation to better see the pattern. They will give the same values I used in the previous example:

svg path {
 transform-origin: 12.5% 50%;
}

svg path:nth-child(1)  { transform:rotate(calc(0*(180deg/11)));}
svg path:nth-child(2)  { transform:rotate(calc(1*(180deg/11)));}
svg path:nth-child(3)  { transform:rotate(calc(2*(180deg/11)));}
svg path:nth-child(4)  { transform:rotate(calc(3*(180deg/11)));}
svg path:nth-child(5)  { transform:rotate(calc(4*(180deg/11)));}
svg path:nth-child(6)  { transform:rotate(calc(5*(180deg/11)));}
svg path:nth-child(7)  { transform:rotate(calc(6*(180deg/11)));}
svg path:nth-child(8)  { transform:rotate(calc(7*(180deg/11)));}
svg path:nth-child(9)  { transform:rotate(calc(8*(180deg/11)));}
svg path:nth-child(10) { transform:rotate(calc(9*(180deg/11)));}
svg path:nth-child(11) { transform:rotate(calc(10*(180deg/11)));}

body {
  background: pink;
}
<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256'> 
<path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' />
<path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' />
<path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' />
<path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' />
<path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' />
<path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' />
<path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' />
<path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' />
<path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' />
<path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' />
<path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' />
</svg>

Here is another attempt with more spikes and closer to your example. I simply reduced the width of the pattern by 2 and I increased their number by two:

svg path {
 transform-origin: 12.5% 50%;
}

svg path:nth-child(1)  { transform:rotate(calc(0*(180deg/22)));}
svg path:nth-child(2)  { transform:rotate(calc(1*(180deg/22)));}
svg path:nth-child(3)  { transform:rotate(calc(2*(180deg/22)));}
svg path:nth-child(4)  { transform:rotate(calc(3*(180deg/22)));}
svg path:nth-child(5)  { transform:rotate(calc(4*(180deg/22)));}
svg path:nth-child(6)  { transform:rotate(calc(5*(180deg/22)));}
svg path:nth-child(7)  { transform:rotate(calc(6*(180deg/22)));}
svg path:nth-child(8)  { transform:rotate(calc(7*(180deg/22)));}
svg path:nth-child(9)  { transform:rotate(calc(8*(180deg/22)));}
svg path:nth-child(10) { transform:rotate(calc(9*(180deg/22)));}
svg path:nth-child(11) { transform:rotate(calc(10*(180deg/22)));}
svg path:nth-child(12) { transform:rotate(calc(11*(180deg/22)));}
svg path:nth-child(13) { transform:rotate(calc(12*(180deg/22)));}
svg path:nth-child(14) { transform:rotate(calc(13*(180deg/22)));}
svg path:nth-child(15) { transform:rotate(calc(14*(180deg/22)));}
svg path:nth-child(16) { transform:rotate(calc(15*(180deg/22)));}
svg path:nth-child(17) { transform:rotate(calc(16*(180deg/22)));}
svg path:nth-child(18) { transform:rotate(calc(17*(180deg/22)));}
svg path:nth-child(19) { transform:rotate(calc(18*(180deg/22)));}
svg path:nth-child(20) { transform:rotate(calc(19*(180deg/22)));}
svg path:nth-child(21) { transform:rotate(calc(20*(180deg/22)));}
svg path:nth-child(22) { transform:rotate(calc(21*(180deg/22)));}

body {
  background: pink;
}
<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256'> 
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
<path d='M40 240 L40 16 L32 0 L24 16 L24 240 L32 256 Z' />
</svg>

You can also easily adjust the size of the spikes.

svg path {
 transform-origin: 12.5% 50%;
}

svg path:nth-child(1)  { transform:rotate(calc(0*(180deg/11)));}
svg path:nth-child(2)  { transform:rotate(calc(1*(180deg/11)));}
svg path:nth-child(3)  { transform:rotate(calc(2*(180deg/11)));}
svg path:nth-child(4)  { transform:rotate(calc(3*(180deg/11)));}
svg path:nth-child(5)  { transform:rotate(calc(4*(180deg/11)));}
svg path:nth-child(6)  { transform:rotate(calc(5*(180deg/11)));}
svg path:nth-child(7)  { transform:rotate(calc(6*(180deg/11)));}
svg path:nth-child(8)  { transform:rotate(calc(7*(180deg/11)));}
svg path:nth-child(9)  { transform:rotate(calc(8*(180deg/11)));}
svg path:nth-child(10) { transform:rotate(calc(9*(180deg/11)));}
svg path:nth-child(11) { transform:rotate(calc(10*(180deg/11)));}

body {
  background: pink;
}
<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256'> 
<path d='M48 220 L48 36 L32 0 L16 36 L16 220 L32 256 Z' />
<path d='M48 220 L48 36 L32 0 L16 36 L16 220 L32 256 Z' />
<path d='M48 220 L48 36 L32 0 L16 36 L16 220 L32 256 Z' />
<path d='M48 220 L48 36 L32 0 L16 36 L16 220 L32 256 Z' />
<path d='M48 220 L48 36 L32 0 L16 36 L16 220 L32 256 Z' />
<path d='M48 220 L48 36 L32 0 L16 36 L16 220 L32 256 Z' />
<path d='M48 220 L48 36 L32 0 L16 36 L16 220 L32 256 Z' />
<path d='M48 220 L48 36 L32 0 L16 36 L16 220 L32 256 Z' />
<path d='M48 220 L48 36 L32 0 L16 36 L16 220 L32 256 Z' />
<path d='M48 220 L48 36 L32 0 L16 36 L16 220 L32 256 Z' />
<path d='M48 220 L48 36 L32 0 L16 36 L16 220 L32 256 Z' />
</svg>


As a side note, I have used path to create the pattern but since it's an easy shape we can also do it with polygon using almost the same syntax:

svg {
 border:1px solid;
}
<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256'> 
<path d='M48 240 L48 16 L32 0 L16 16 L16 240 L32 256 Z' />
</svg>
<svg xmlns='http://www.w3.org/2000/svg' viewBox='-97 0 256 256' fill='orange' width='256'> 
<polygon points='48,240 48,16 32,0 16,16 16,240 32,256' />
</svg>



回答2:

You can create a (jagged) circle with triangles. The idea is to create an equilateral triangle inscribed inside the circle, create copies of it and rotate them around the center. The following figure explains how the sides of the triangle are calculated:

.circle {
  width: 100px;
  height: 100px;
  position: relative;
  background-color: #CCCCCC;
}

/*
 * triangle border left/right = 50px * cos(30°)
 * triangle border bottom = 50px + 50px * sin(30°)
 */

.triangle {
  position: absolute;
  left: 6.7px;
  top: 0;
  width: 0;
  height: 0;
  border-left: 43.3px solid transparent;
  border-right: 43.3px solid transparent;
  border-bottom: 75px solid #BF9020;
  transform-origin: center 50px;
}

.triangle:nth-child(2) { transform: rotate(10deg); }
.triangle:nth-child(3) { transform: rotate(20deg); }
.triangle:nth-child(4) { transform: rotate(30deg); }
.triangle:nth-child(5) { transform: rotate(40deg); }
.triangle:nth-child(6) { transform: rotate(50deg); }
.triangle:nth-child(7) { transform: rotate(60deg); }
.triangle:nth-child(8) { transform: rotate(70deg); }
.triangle:nth-child(9) { transform: rotate(80deg); }
.triangle:nth-child(10) { transform: rotate(90deg); }
.triangle:nth-child(11) { transform: rotate(100deg); }
.triangle:nth-child(12) { transform: rotate(110deg); }
<div class="circle">
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
</div>

Once you're able to get your head around the above example use the fluid version below:

.circle {
  width: 80vh;
  height: 80vh;
  position: relative;
  background-color: #CCCCCC;
}

.triangle {
  position: absolute;
  left: 6.7%;
  top: 0;
  width: 86.6%;
  height: 75%;
  background-color: #BF9020;
  clip-path: polygon(50% 0, 0 100%, 100% 100%);
  transform-origin: center 66.6%;
}

.triangle:nth-child(2) { transform: rotate(10deg); }
.triangle:nth-child(3) { transform: rotate(20deg); }
.triangle:nth-child(4) { transform: rotate(30deg); }
.triangle:nth-child(5) { transform: rotate(40deg); }
.triangle:nth-child(6) { transform: rotate(50deg); }
.triangle:nth-child(7) { transform: rotate(60deg); }
.triangle:nth-child(8) { transform: rotate(70deg); }
.triangle:nth-child(9) { transform: rotate(80deg); }
.triangle:nth-child(10) { transform: rotate(90deg); }
.triangle:nth-child(11) { transform: rotate(100deg); }
.triangle:nth-child(12) { transform: rotate(110deg); }
<div class="circle">
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
  <div class="triangle"></div>
</div>



回答3:

Another solution is to use clip-path property:

.box {
  width: 150px;
  height: 150px;
  background: lightblue;
}

.clipped {
  clip-path: polygon(50% 0%, 46.93% 3.1%, 43.47% 0.43%, 40.83% 3.9%, 37.06% 1.7%, 34.89% 5.49%, 30.87% 3.81%, 29.21% 7.85%, 25% 6.7%, 23.89% 10.92%, 19.56% 10.33%, 19.01% 14.66%, 14.64% 14.64%, 14.66% 19.01%, 10.33% 19.56%, 10.92% 23.89%, 6.7% 25%, 7.85% 29.21%, 3.81% 30.87%, 5.49% 34.89%, 1.7% 37.06%, 3.9% 40.83%, 0.43% 43.47%, 3.1% 46.93%, 0% 50%, 3.1% 53.07%, 0.43% 56.53%, 3.9% 59.17%, 1.7% 62.94%, 5.49% 65.11%, 3.81% 69.13%, 7.85% 70.79%, 6.7% 75%, 10.92% 76.11%, 10.33% 80.44%, 14.66% 80.99%, 14.64% 85.36%, 19.01% 85.34%, 19.56% 89.67%, 23.89% 89.08%, 25% 93.3%, 29.21% 92.15%, 30.87% 96.19%, 34.89% 94.51%, 37.06% 98.3%, 40.83% 96.1%, 43.47% 99.57%, 46.93% 96.9%, 50% 100%, 53.07% 96.9%, 56.53% 99.57%, 59.17% 96.1%, 62.94% 98.3%, 65.11% 94.51%, 69.13% 96.19%, 70.79% 92.15%, 75% 93.3%, 76.11% 89.08%, 80.44% 89.67%, 80.99% 85.34%, 85.36% 85.36%, 85.34% 80.99%, 89.67% 80.44%, 89.08% 76.11%, 93.3% 75%, 92.15% 70.79%, 96.19% 69.13%, 94.51% 65.11%, 98.3% 62.94%, 96.1% 59.17%, 99.57% 56.53%, 96.9% 53.07%, 100% 50%, 96.9% 46.93%, 99.57% 43.47%, 96.1% 40.83%, 98.3% 37.06%, 94.51% 34.89%, 96.19% 30.87%, 92.15% 29.21%, 93.3% 25%, 89.08% 23.89%, 89.67% 19.56%, 85.34% 19.01%, 85.36% 14.64%, 80.99% 14.66%, 80.44% 10.33%, 76.11% 10.92%, 75% 6.7%, 70.79% 7.85%, 69.13% 3.81%, 65.11% 5.49%, 62.94% 1.7%, 59.17% 3.9%, 56.53% 0.43%, 53.07% 3.1%);
}
<div class="box clipped"></div>

As mentioned in another answer - the tricky part is figuring out the right values. I didn't pick them by hand - check this codepen to see how they are generated.