Notched Boxes

Avatar of Chris Coyier
Chris Coyier on

Say you’re trying to pull off a design effect where the corner of an element are cut off. Maybe you’re a Battlestar Galactica fan? Or maybe you just like the unusual effect of it, since it avoids looking like a typical rectangle.

I suspect there are many ways to do it. Certainly, you could use multiple backgrounds to place images in the corners. You could just as well use a flexible SVG shape placed in the background. I bet there is also an exotic way to use gradients to pull it off.

But, I like the idea of simply taking some scissors and clipping off the dang corners. We essentially can do just that thanks to clip-path. We can use the polygon() function, provide it a list of X and Y coordinates and clip away what is outside of them.

Check out what happens if we list three points: middle top, bottom right, bottom left.

.module {
  clip-path: 
    polygon(
      50% 0,
      100% 100%,
      0 100%
    );
}

Instead of just three points, let’s list all eight points needed for our notched corners. We could use pixels, but that would be dangerous. We probably don’t really know the pixel width or height of the element. Even if we did, it could change. So, here it is using percentages:

.module {
  clip-path: 
    polygon(
      0% 5%,     /* top left */
      5% 0%,     /* top left */
      95% 0%,    /* top right */
      100% 5%,   /* top right */
      100% 95%,  /* bottom right */
      95% 100%,  /* bottom right */
      5% 100%,   /* bottom left */
      0 95%      /* bottom left */
    );
}

That’s OK, but notice how the notches aren’t at perfect 45 degree angles. That’s because the element itself isn’t a square. That gets worse the less square the element is.

We can use the calc() function to fix that. We’ll use percentages when we have to, but just subtract from a percentage to get the position and angle we need.

.module {
  clip-path: 
    polygon(
      0% 20px,                 /* top left */
      20px 0%,                 /* top left */
      calc(100% - 20px) 0%,    /* top right */
      100% 20px,               /* top right */
      100% calc(100% - 20px),  /* bottom right */
      calc(100% - 20px) 100%,  /* bottom right */
      20px 100%,               /* bottom left */
      0 calc(100% - 20px)      /* bottom left */
    );
}

And you know what? That number is repeated so many times that we may as well make it a variable. If we ever need to update the number later, then all it takes is changing it once instead of all those individual times.

.module {
  --notchSize: 20px;
  
  clip-path: 
    polygon(
      0% var(--notchSize), 
      var(--notchSize) 0%, 
      calc(100% - var(--notchSize)) 0%, 
      100% var(--notchSize), 
      100% calc(100% - var(--notchSize)), 
      calc(100% - var(--notchSize)) 100%, 
      var(--notchSize) 100%, 
      0% calc(100% - var(--notchSize))
    );
}

Ship it.

See the Pen Notched Boxes by Chris Coyier (@chriscoyier) on CodePen.

This may go without saying, but make sure you have enough padding to handle the clipping. If you wanna get really fancy, you might use CSS variables in your padding value as well, so the more you notch, the more padding there is.