alt alt

CSS Shapes

Hey there, CSS fans! It’s a growing collection of shape tricks, all crafted using pure CSS. Each shape comes with code snippets, so you can easily integrate them and experiment with different approaches.

There are many reasons to use CSS shapes instead of SVG, here you can find different examples and useful links.

Border radius

This property is quite simple but very useful. Unfortunately, it cannot draw a squircle… yet.

.circle {
  width: 100px;
  aspect-ratio: 1/1;
  border-radius: 50%;
  background: #FFFFFF;
}
.ellipse {
  width: 100px;
  aspect-ratio: 2/1;
  border-radius: 50%;
  background: #FFFFFF;
}
.sausage {
  width: 100px;
  aspect-ratio: 2/1;
  /* 99em, 100vw, or any other big number */
  border-radius: 99em;
  background: #FFFFFF;
}
.semicircle {
  width: 100px;
  aspect-ratio: 2/1;
  /* don't use % here,
     use big number or height */
  border-radius: 50px 50px 0 0;
  background: #FFFFFF;
}
.quadrant {
  width: 100px;
  aspect-ratio: 1/1;
  border-radius: 0 100% 0 0;
  background: #FFFFFF;
}
.leaf {
  width: 100px;
  aspect-ratio: 1/1;
  border-radius: 0 100%;
  background: #FFFFFF;
}
.blob {
  width: 100px;
  aspect-ratio: 1/1;
  /* watch https://www.youtube.com/watch?v=Q8HZqdrhlVc
     to see how it works */
  border-radius: 40% 60% 30% 70% / 
                 35% 50% 50% 65%;
  background: #FFFFFF;
}

Box-shadow

✅ This property can help you to copy the shape of your block.

✅ It copies a shape even if the block doesn’t have a background.

✅ It draws a shape both inside and ouside of the block.

✅ The shadow could be bigger or smaller than the original block. It controls by the spread value box-shadow: x y blur spread color.

✅ There could be any amount of shadows.

⚠️ It copies the shape of the root element. Chindren don’t affect the shape of the shadow.

❌ The shadow is not visible behind the root element even if it has no background.

❌ Can’t copy the complex shape.

Pixelate image generator

.inner-shadows {
  width: 100px;
  aspect-ratio: 1/1;
  border-radius: 50%;
  /* there could be any number of shadows */
  box-shadow:
    inset 0 0 0 5px rgba(255 255 255 / .4),
    inset 0 0 0 15px rgba(255 255 255 / .4),
    inset 0 0 0 30px rgba(255 255 255 / .4);
}
.shifted-shadow {
  width: 100px;
  aspect-ratio: 1/1;
  border-radius: 50%;
  /* there could be any number of shadows */
  box-shadow:
    inset 10px 10px 0 10px rgba(255 255 255 / .4),
    inset 10px 10px 0 20px rgba(255 255 255 / .4),
    inset 10px 10px 0 30px rgba(255 255 255 / .4);
}
.outer-shadows {
  width: 100px;
  aspect-ratio: 1/1;
  border-radius: 50%;
  /* you can use both inner and outer shadows */
  box-shadow:
    10px 10px 0 10px rgba(255 255 255 / .4),
    10px 10px 0 20px rgba(255 255 255 / .4),
    10px 10px 0 30px rgba(255 255 255 / .4);
}
.moon {
  width: 100px;
  aspect-ratio: 1/1;
  border-radius: 50%;
  box-shadow:
    inset 50px -40px 0 -20px #FFFFFF;
}
.duplication {
  width: 100px;
  aspect-ratio: 1/1;
  border-radius: 50%;
  border: 2px solid #FFFFFF;
  /* shadow could be bigger or smaller
     change the fourth number to do it */
  box-shadow:
    -100px 0 0 10px #FFFFFF,
     100px 0 0 -10px #FFFFFF;
  /* this block doesn't have a background
     but you can't see the shadow through */
}
.mario {
  width: 10px;
  height: 10px;
  box-shadow: 
    20px 0 #F63911, 30px 0 #F63911, 50px 0 #F63911, 50px 0 #F63911, 60px 0 #F63911, 10px 10px #F63911, 
    20px 10px #F63911, 40px 0px #F63911, 30px 10px #F63911, 40px 10px #F63911, 50px 10px #F63911, 60px 10px #F63911, 
    70px 10px #F63911, 90px 10px #F63911, 10px 20px #8C5610, 20px 20px #8C5610, 30px 20px #8C5610, 10px 30px #8C5610, 
    0px 30px #8C5610, 0px 40px #8C5610, 20px 40px #8C5610, 30px 40px #8C5610, 0px 50px #8C5610, 10px 50px #8C5610,
    10px 30px #FFB56B, 10px 40px #FFB56B, 40px 40px #FFB56B, 40px 30px #FFB56B, 30px 30px #FFB56B, 40px 20px #FFB56B, 
    50px 20px #FFB56B, 50px 30px #FFB56B, 50px 40px #FFB56B, 50px 50px #FFB56B, 40px 50px #FFB56B, 30px 50px #FFB56B, 
    20px 50px #FFB56B, 20px 60px #FFB56B, 30px 60px #FFB56B, 40px 60px #FFB56B, 50px 60px #FFB56B, 60px 60px #FFB56B, 
    70px 60px #FFB56B, 80px 60px #FFB56B, 80px 40px #FFB56B, 60px 40px #FFB56B, 90px 40px #FFB56B, 100px 40px #FFB56B, 
    90px 30px #FFB56B, 80px 30px #FFB56B, 70px 30px #FFB56B, 70px 20px #FFB56B, 60px 20px #000000, 60px 30px #000000, 
    70px 40px #000000, 60px 50px #000000, 70px 50px #000000, 80px 50px #000000, 90px 50px #000000, 80px 10px #F63911, 20px 30px #FFB56B;
}

Drop shadow

✅ This property can help you to copy the shape of your block.

✅ Can’t copy the complex shape.

✅ There could be any amount of shadows.

✅ The shadow is visible behind the root element.

⚠️ It copies all the non-transparent pixels within this block.

⚠️ It copies the shape of the root element and all the chindren inside.

⚠️ Every next drop-shadow copies the shape of the original block and all the shadows before.

❌ It draws a shape only ouside of the block.

❌ The shadow could only be the same size as the original block.

.duplication {
  width: 100px;
  aspect-ratio: 1/1;
  border-radius: 50%;
  border: 2px solid #FFFFFF;
  filter: drop-shadow(0px 40px 0 #FFFFFF);
}
.duplication {
  width: 100px;
  aspect-ratio: 1/1;
  border-radius: 50%;
  border: 2px solid #FFFFFF;
  filter: drop-shadow(0px 40px 0 #00CECB) 
          drop-shadow(40px 0 0 #FF5E5B);
}
.duplication {
  width: 100px;
  aspect-ratio: 1/1;
  border-radius: 50%;
  border: 2px solid #FFFFFF;
  filter: drop-shadow(0px 40px 0 #FF5E5B);
}
.duplication::before {
  content: '';
  display: block;
  width: 90%; aspect-ratio: 1 / 1;
  margin: 5%;
  background-color: #FFFFFF;
  rotate: 45deg;
}

Mask

Masks create a clipping region that defines which part of an element should be visible. Parts within the region are shown, while those outside are hidden. If you’ve eved used a background to draw a gradient, you already know how to use mask. There are the same family-propeties: mask-image, mask-position, mask-size, mask-repeat.

.mask {
  width: 100px;
  aspect-ratio: 1/1;
  background-color: #FFFFFF;
  mask-image: linear-gradient(45deg, black 50%, transparent 50%);
}
.mask {
  width: 100px;
  aspect-ratio: 1/1;
  background-color: #FFFFFF;
  mask-image: linear-gradient(45deg, black 50%, transparent 50%);
  mask-size: 10px 10px;
}
.mask {
  width: 100px;
  aspect-ratio: 1/1;
  background-color: #FFFFFF;
  mask-image: radial-gradient(closest-side, white 100%, transparent 0),
              linear-gradient(45deg, black 50%, transparent 50%);
}

Clip path

Masks create a clipping region that defines which part of an element should be visible. Parts within the region are shown, while those outside are hidden.

Clip-path generator

Clip-path stars generator

Clip-path wawes generator

Clip-path polygons generator

.mask {
  width: 100px;
  aspect-ratio: 1/1;
  background-color: #FFFFFF;
  clip-path: circle(50% at 50% 50%);
}
.mask {
  width: 100px;
  aspect-ratio: 2/1;
  background-color: #FFFFFF;
  clip-path: ellipse(50% 50% at 50% 50%);
}
.mask {
  width: 100px;
  aspect-ratio: 1/1;
  background-color: #FFFFFF;
  clip-path: polygon(50% 0, 70% 25%, 100% 38%, 
             83% 66%, 81% 100%, 50% 92%, 19% 100%, 
             17% 67%, 0 38%, 30% 25%);
}

Background

The most powerful property. You can create a world with just a gradient and one block!

Gradient patterns

.background {
  width: 100px;
  aspect-ratio: 1/1;
  background-image: linear-gradient(0deg, #FFFFFF 2px, transparent 2px 4px);
  background-size: 100% 4px;
}
.background {
  width: 100px;
  aspect-ratio: 1/1;
  background-image: radial-gradient(closest-side, #FFFFFF 100%, transparent 0);
  background-size: 10px 10px;
}
.background {
  width: 100px;
  aspect-ratio: 1/1;
  background-image: conic-gradient(#FFFFFF 45deg, transparent 45deg 135deg,
                    #FFFFFF 135deg 225deg, transparent 225deg 315deg, #FFFFFF 315deg);
  background-size: 10px 10px;
}
.background {
  width: 100px;
  aspect-ratio: 1/1;
  background-image: radial-gradient(closest-side, #FFFFFF 100%, transparent 0),
                    radial-gradient(closest-side, #FFFFFF 100%, transparent 0),
                    linear-gradient(#FFFFFF, #FFFFFF);
  background-position: 25% 0px, 75% 0px, 0px 100%;
  background-size: 30% 60%, 30% 60%, 100% 20%;
  background-repeat: no-repeat;
}

Transform

.transform {
  width: 100px;
  aspect-ratio: 1/1;
  background-color: #FFFFFF;
  rotate: 45deg;
}
.transform {
  width: 100px;
  aspect-ratio: 1/1;
  background-color: #FFFFFF;
  transform: skew(10deg);
}

Border

This approach is useful for blocks with no content and plain background.

.border {
  border-style: solid;
  border-color: transparent transparent #FFFFFF;
  border-width: 0 50px 100px;
}
.border {
  border-style: solid;
  border-color: transparent transparent #FFFFFF;
  border-width: 0 0 100px 100px;
}
.border {
  width: 30%;
  border-style: solid;
  border-color: transparent transparent #FFFFFF transparent;
  border-width: 0 20px 100px 20px;
}