I got here throughout Kitty Giraudel’s folded corners method. It leverages CSS clip-path, and I assumed that that was such a cool approach to do it. clip-path has been trending currently, almost definitely as a result of net browsers help the form() perform now.
Nonetheless, I’ve been on a little bit of a corner-shape kick currently (take a look at my introduction to corner-shape in addition to these scroll-driven corner-shape animations), so I figured that corner-shape could possibly be used to create folded corners as nicely, and that is what I got here up with:
So open Chrome, which helps corner-shape, and let’s dig in (in the event you’re this in different browsers, it principally falls again to a rounded nook).
Step 1: Set some CSS variables
Components have 4 corners, however after we use border-radius, every nook is break up into two coordinates. The x-axis coordinate strikes alongside the x-axis, away from its related nook, whereas the y-axis coordinate does the identical factor alongside the y-axis. It’s from these coordinates that border-radius attracts the curvature of the rounded corners.

First, retailer the coordinates as CSS variables. We’ll want the values that they maintain greater than as soon as, so this simplifies issues, makes the fold animatable, and maintains some extent of realism.
:root {
/* x-axis coordinate */
--x-coord: 9rem;
/* y-axis coordinate */
--y-coord: 5rem;
}
Step 2: Establishing the fold
Given what we now find out about border-radius, it needs to be apparent what border-top-right-radius does. As for corner-top-right-shape: bevel, that ensures {that a} straight line is drawn between the coordinates as an alternative of rounded corners (corner-top-right-shape: spherical). That’s proper, border-radius consists of corner-shape: spherical by default (behind the scenes, after all).
/* Sq. */
div {
/* Place coordinates */
border-top-right-radius: var(--x-coord) var(--y-coord);
/* Draw line between coordinates */
corner-top-right-shape: bevel;
}

Step 3: Creating the flip facet
Now that we’ve established the fold, it’s time to create the flip facet. Begin by deciding on ::earlier than, then declare content material: "" to create the aspect with out content material. The background could be inherited from the sq., and the scale ought to leverage the coordinates that we saved. As you may see, I’ve additionally added a box-shadow the place the blur radius scales with --x-coord and --y-coord, however you’re welcome to adapt the components as you see match.
/* Sq. */
div {
/* Place coordinates */
border-top-right-radius: var(--x-coord) var(--y-coord);
/* Draw line between coordinates */
corner-top-right-shape: bevel;
/* Flip facet */
&::earlier than {
/* Generate empty aspect */
content material: "";
/* Inherit background */
background: inherit;
/* Similar as coordinates */
width: var(--x-coord);
peak: var(--y-coord);
/* Scale blur radius with --x-coord and --y-coord */
box-shadow: 0 0 calc((var(--x-coord) + var(--y-coord)) / 3) #00000050;
}
}

Step 4: Positioning the flip facet (::earlier than)
Subsequent, we have to shift ::earlier than to the (top-)proper nook. We’re avoiding anchor positioning, as a result of there’s no want for contemporary options if extra supported options work nicely utilizing the identical quantity of code. So, declare place: relative on the sq. and place: absolute on ::earlier than. This makes ::earlier than place relative to the sq., and is a trick that solely works for parent-child relationships. Really, this shortcoming is why anchor positioning was invented, however we simply don’t want it on this case.
As well as, declare inset: 0 0 auto auto on ::earlier than to align it to the top-right nook of the sq., and overflow: clip on the sq. to clip the half of ::earlier than that overflows it.
/* Sq. */
div {
/* Place coordinates */
border-top-right-radius: var(--x-coord) var(--y-coord);
/* Draw line between coordinates */
corner-top-right-shape: bevel;
/* Clip any overflow */
overflow: clip;
/* For alignment */
place: relative;
/* Flip facet */
&::earlier than {
/* Generate empty aspect */
content material: "";
/* Inherit background */
background: inherit;
/* Similar as coordinates */
width: var(--x-coord);
peak: var(--y-coord);
/* Scale blur radius with --x-coord and --y-coord */
box-shadow: 0 0 calc((var(--x-coord) + var(--y-coord)) / 3) #00000050;
/* For alignment */
place: absolute;
/* Align to top-right */
inset: 0 0 auto auto;
}
}

You’ll be able to cease right here in order for you, however there’s room for enchancment…
Step 5: Sculpting the flip facet
To make the end result look a bit extra lifelike, we’ll use corner-bottom-left-shape: bevel to make yet another straight reduce, this time to ::earlier than. There are, almost definitely, some ways to deal with this relying on how sharply we wish to crease the fold, how elevated we would like the flip facet to be, and the angle from which we wish to view the sq., however I don’t assume it issues so long as the impact seems respectable, so we’re aiming for a pointy crease, the flip facet sticking up, and an aerial view. In case you’d somewhat one thing totally different, remember the fact that the shadow additionally impacts the end result, and that you just’d be going through a trickier implementation.
The one diploma of complexity that I recommend is that this:
/* Guarantee lifelike fold */
@container type(--x-coord < --y-coord) {
border-bottom-left-radius: 100% calc(100% - var(--x-coord));
}
@container type(--x-coord >= --y-coord) {
border-bottom-left-radius: calc(100% - var(--y-coord)) 100%;
}
These are container type queries utilizing the vary syntax, the place if the worth of --x-coord is lower than the worth of --y-coord, we subtract the worth of --x-coord from 100% and use it because the y-axis coordinate for the related border radius (border-bottom-left-radius, on this case). The opposite axis is about to 100%. Adversely, if the worth of --x-coord is extra than (or equal to) the worth of --y-coord, we subtract the worth of --y-coord from 100% and use it because the x-axis coordinate. As soon as once more, the opposite axis is about to 100%.
The result’s that the crease, shadow, and now perspective of the fold is calculated utilizing solely --x-coord and --y-coord to look lifelike (or lifelike sufficient, anyway). Utilizing the slideVars toggles within the top-right nook of the demo, you may see for your self by testing numerous combos of coordinates:
If you wish to implement a failsafe to make sure that the coordinates don’t exceed the scale of the sq., breaking the impact, you need to use min(). The modified coordinate variables under set --y-coord to an unimaginable 999999999rem, however caps it on the peak of the sq. (though I can’t think about that you just’d really need this, to be utterly sincere):
--x-coord: min(--square-width, 9rem);
--y-coord: min(--square-height, 999999999rem);

All in all, we’ve not solely a folded nook impact however a utility that builds the impact primarily based on solely two coordinates.
The total code:
:root {
/* x-axis coordinate */
--x-coord: 9rem;
/* y-axis coordinate */
--y-coord: 5rem;
/* Sq. */
div {
/* Place coordinates */
border-top-right-radius: var(--x-coord) var(--y-coord);
/* Draw line between coordinates */
corner-top-right-shape: bevel;
/* Clip any overflow */
overflow: clip;
/* For alignment */
place: relative;
/* Flip facet */
&::earlier than {
/* Generate empty aspect */
content material: "";
/* Inherit background */
background: inherit;
/* Similar as coordinates */
width: var(--x-coord);
peak: var(--y-coord);
/* Scale blur radius with --x-coord and --y-coord */
box-shadow: 0 0 calc((var(--x-coord) + var(--y-coord)) / 3) #00000050;
/* For alignment */
place: absolute;
/* Align to top-right */
inset: 0 0 auto auto;
/* Draw line between coordinates */
corner-bottom-left-shape: bevel;
/* Guarantee lifelike fold */
@container type(--x-coord < --y-coord) {
border-bottom-left-radius: 100% calc(100% - var(--x-coord));
}
@container type(--x-coord >= --y-coord) {
border-bottom-left-radius: calc(100% - var(--y-coord)) 100%;
}
}
}
}
Observe: We may swap container type queries for if() capabilities, that are shorter however much less readable.
Folded corners utilizing clip-path vs. corner-shape
Kitty’s Giraudel’s folded corners work in all browsers, and since clip-path is used, which is a extra versatile shaping function, there are extra methods to customise the form. It’s additionally the extra right strategy, for no matter that’s value. Nonetheless, my corner-shape strategy is cleaner and certain wouldn’t require any additional customization anyway, however lacks Safari and Firefox help for now. So until you want folded corners in the present day, I’d bookmark each:
