Curved Box Cutouts in CSS

Preethi Sam Preethi Sam on

This post explores a trick to create the illusion of an element appended to another with a gap and curved edges at the corners. It’s useful for visually demarcating supplementary elements or user controls in a card module.

An example:

The Layout

Let’s start with the HTML and code a simple design.

<div class="outer">
  <div class="inner"></div>
</div>Code language: HTML, XML (xml)

Use a nested element (.inner) or a stacked element to create the small box. The key is for the small box to overlap the larger one.

.outer {
  width: 375px;
  aspect-ratio: 1;
  border-radius: 12px;
  background: dodgerblue;

  .inner {
    width: 160px;
    height: 60px;
    border-radius: inherit;
    background: skyblue;
  }
}Code language: CSS (css)

The larger square box (.outer) and the smaller rectangle box (.inner) share the same border-radius value (12px).

The Smaller Box

Add an outline of the same color as the page.

.inner {
  /* etc. */
  outline: 8px solid white;
}Code language: CSS (css)

That’s all we need to do with the inner box.

The Bigger Box

Add two small radial-gradient() background images to the larger box’s background.

  1. Position the images where the smaller box’s corners overlap, with a negative offset equal to the outline size (8px).
  2. The border radius (12px) plus the smaller box’s outline (8px) equals the images’ size (20px 20px).
  3. The gradients are transparent circles the same size as the border radius (12px), with the rest white
.outer {
  /* etc. */
  background: 
    -8px 60px / 20px 20px 
        radial-gradient(circle at right bottom, transparent 12px, white 12px),
    160px -8px / 20px 20px 
        radial-gradient(circle at right bottom, transparent 12px, white 12px),
    dodgerblue;
}Code language: CSS (css)

The code is complete. You’ll get the final result as is. However, let’s make the code more flexible.

CSS Variables

For ease of update, I’ll move the length values to CSS variables, and for clarity, I’ll list each of the background- properties separately.

.outer {
  width: 375px;
  aspect-ratio: 1;

  /* border radius */
  --r: 12px;

  /* width, height, and outline of smaller box */
  --w: 160px;
  --h: 60px;
  --o: 8px;

  /* offset and size of the radial-gradient images */
  --ofs: calc(-1 * var(--o));
  --sz: calc(var(--r) + var(--o));
  --img: radial-gradient(circle at right bottom, transparent var(--r), white var(--r));

  border-radius: var(--r);
  background-image: var(--img), var(--img);
  background-position: var(--ofs) var(--h), var(--w) var(--ofs);
  background-size: var(--sz) var(--sz);
  background-repeat: no-repeat;
  background-color: dodgerblue;

  .inner {
    width: var(--w);
    height: var(--h);
    outline: var(--o) solid white;
    border-radius: inherit;
    background: skyblue;
  }
}Code language: CSS (css)

All Four Corner Placements

Place the smaller box in the desired corner against the bigger one, and update the radial gradient image positions and circles accordingly.

.outer {
  /* etc. */
  background-image:
   radial-gradient(circle at var(--cnr), transparent var(--r), white var(--r)),
   radial-gradient(circle at var(--cnr), transparent var(--r), white var(--r)),
   linear-gradient(45deg, rgb(210, 223, 246), rgb(51, 134, 242));

  &:nth-of-type(1) {
    --cnr: right bottom;
    background-position: 
      var(--ofs) var(--h), 
      var(--w) var(--ofs), 
      0 0;
    /* etc. */
  }

  &:nth-of-type(2) {
    --cnr: left bottom;
    background-position: 
      calc(100% - var(--ofs)) var(--h), 
      calc(100% - var(--w)) calc(var(--ofs)), 
      0 0;
    /* etc. */
  }

  &:nth-of-type(3) {
    --cnr: left top;
    background-position: 
      calc(100% - var(--ofs)) calc(100% - var(--h)), 
      calc(100% - var(--w)) calc( 100% - var(--ofs)), 
      0 0;
    /* etc. */
  }

  &:nth-of-type(4) {
    --cnr: right top;
    background-position: 
      var(--ofs) calc(100% - var(--h)), 
      var(--w) calc(100% - var(--ofs)), 
      0 0;
    /* etc. */
  }
}Code language: CSS (css)

The larger box in the example is a square, so 100% is used in calculating the radial gradient images’ positions both vertically and horizontally where needed.

How to Use The Design?

Since the design uses an imitation of a gap, effects like drop shadow that require cutouts won’t work. However, no extra markup or style changes are needed, only the background is affected, making it suitable for simple designs.

This doesn’t have to be limited to gap-like designs, either. The outline can be used in other ways, too. The rounded corners will be a subtle touch up.

.date {
  outline: var(--outline) solid navy;
  /* etc. */
}Code language: CSS (css)

Need front-end development training?

Frontend Masters logo

Frontend Masters is the best place to grow in your career as a developer. We have courses on all the most important front-end technologies and beyond, from React to CSS, to backend with Node.js and Full Stack.

7-Day Free Trial

Leave a Reply

Your email address will not be published. Required fields are marked *

Did you know?

Frontend Masters Donates to open source projects. $363,806 contributed to date.