The Daily TIL

March 8, 2019 by AndyAndycssshapes

Building a curvy container with CSS

Design problem:

ScreenCapture at Sat Mar 9 11:36:26 PST 2019

The white background underneath the call-to-action was an interesting problem. I could have easily exported it as an image or SVG from the design tool, and used this export as a background image. That would have led to some annoying layering problems with the darker banner background, so probably I could have exported the entire top banner, dark and rounded light, as one image. But that would have required two images, one for mobile, one for desktop.

Both seem wasteful if you can do the rounded white background with pure css.

Example

The rounded edge

I figured out pretty quickly how to make a circular container using border-radius: 50%.

const Header = styled.section`
  box-sizing: border-box;
  position: relative;
  height: 350px;
`;

const Bubble = styled.div`
  box-sizing: border-box;
  position: absolute;
  background-color: #f00;
  text-align: center;

  border-radius: 50%;
  height: 700px;
  width: 700px;
`;
<Header>
  <BackgroundImage src={banner} />
  <Bubble>
    <p>
...
    </p>
  </Bubble>
</Header>

ScreenCapture at Sat Mar 9 13:15:22 PST 2019

Positioning

Super-easy, but we don’t want a circle. We want a mostly-rectangular container with one curved edge. So we need to get clever with positioning and sizing.

First we inflate the circle and use some negative margin to position its origin off-view down and to the right so that the left-edge is where we want it.

const Bubble = styled.div`
  box-sizing: border-box;
  position: absolute;
  background-color: #f00;
  text-align: center;
  border-radius: 50%;

  height: 700px;  width: 700px;  top: -60px;  right: -250px;  bottom: 0;  `;

ScreenCapture at Sat Mar 9 12:46:58 PST 2019

Masking the edges

Now we just need to make it look like it has 3 straight edges and one curved edge. We can treat the parent container as a clipping-mask by just hiding overflow.

const Container = styled.section`
  box-sizing: border-box;
  position: relative;
  overflow: hidden;`;

ScreenCapture at Sat Mar 9 13:21:07 PST 2019

Centering the content

The content is obviously not where we want it to be wit respect to the visible container. So you can use padding inside the circle-div to position the content where you want it.

const Bubble = styled.div`
  box-sizing: border-box;  position: absolute;
  background-color: #f00;
  text-align: center;

  border-radius: 50%;
  height: 700px;
  width: 700px;
  top: -60px;
  right: -250px;
  bottom: 0;  
  
  padding: 200px 300px 0 100px;`;

ScreenCapture at Sat Mar 9 13:22:32 PST 2019

Using box-sizing: border-box here will make sizing and padding easier to understand, as the total width/height of the circle will remain the same when you adjust the padding. Otherwise, you’ll have to adjust your desired sizing to take the padding into account.

border-box tells the browser to account for any border and padding in the values you specify for an element’s width and height. If you set an element’s width to 100 pixels, that 100 pixels will include any border or padding you added, and the content box will shrink to absorb that extra width. This typically makes it much easier to size elements.

The Result

After adding some media queries to re-position the circle for small screens, here’s the final result.

bubble

Check out the full example on CodeSandbox.

References