惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
博客园 - 【当耐特】
博客园 - 三生石上(FineUI控件)
量子位
aimingoo的专栏
aimingoo的专栏
V
V2EX
Vercel News
Vercel News
B
Blog
M
MIT News - Artificial intelligence
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Hacker News: Ask HN
Hacker News: Ask HN
TaoSecurity Blog
TaoSecurity Blog
N
News and Events Feed by Topic
D
DataBreaches.Net
Blog — PlanetScale
Blog — PlanetScale
S
Secure Thoughts
U
Unit 42
博客园 - 叶小钗
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Hacker News - Newest:
Hacker News - Newest: "LLM"
N
News | PayPal Newsroom
Help Net Security
Help Net Security
S
Security Affairs
Microsoft Security Blog
Microsoft Security Blog
W
WeLiveSecurity
博客园 - Franky
Forbes - Security
Forbes - Security
Microsoft Azure Blog
Microsoft Azure Blog
博客园_首页
Schneier on Security
Schneier on Security
I
InfoQ
B
Blog RSS Feed
大猫的无限游戏
大猫的无限游戏
A
About on SuperTechFans
Webroot Blog
Webroot Blog
AWS News Blog
AWS News Blog
Last Week in AI
Last Week in AI
Security Archives - TechRepublic
Security Archives - TechRepublic
C
CERT Recently Published Vulnerability Notes
N
News and Events Feed by Topic
阮一峰的网络日志
阮一峰的网络日志
L
Lohrmann on Cybersecurity
SecWiki News
SecWiki News
Recent Commits to openclaw:main
Recent Commits to openclaw:main
J
Java Code Geeks

CSS-Tricks

writing-mode | CSS-Tricks pointer-events | CSS-Tricks What’s !important #15: Boundary-aware CSS, Time-based CSS, Full-bleed CSS, and More | CSS-Tricks Get Ready For the Powerful CSS border-shape Property! | CSS-Tricks What’s !important #14: Gap Decorations, random(), <select> field sizing, and More | CSS-Tricks The Shifting Line Between CSS States and JavaScript Events | CSS-Tricks translateZ() | CSS-Tricks translateY() | CSS-Tricks translateX() | CSS-Tricks translate() | CSS-Tricks Using Scroll-Driven Animations for Opposing Scroll Directions | CSS-Tricks A First Look at Scroll-Triggered Animations | CSS-Tricks The Siren Song of  ariaNotify() | CSS-Tricks Prop For That | CSS-Tricks What’s !important #13: @function, alpha(), CSS Wordle, and More | CSS-Tricks There’s no need to include ‘navigation’ in your navigation labels | CSS-Tricks Why Isn't My 3D View Transition Working? | CSS-Tricks Creating Memorable Web Experiences: A Modern CSS Toolkit | CSS-Tricks Scroll-Driven, Scroll-Triggered, Scroll States, and View Transitions | CSS-Tricks Another Stab at the Perfect CSS Pie Chart... Sans JavaScript! | CSS-Tricks offset-path | CSS-Tricks @custom-media | CSS-Tricks @function | CSS-Tricks ::search-text | CSS-Tricks Astro Markdown Component Utility for Any Framework | CSS-Tricks What’s !important #12: Safari Testing, ::checkmark, HTML Anchor Positioning, and More | CSS-Tricks Revealing Text With CSS letter-spacing | CSS-Tricks Technical Writing in the AI Age | CSS-Tricks Cross-Document View Transitions: Scaling Across Hundreds of Elements | CSS-Tricks The State of CSS Centering in 2026 | CSS-Tricks Stack Overflow: When We Stop Asking | CSS-Tricks Cross-Document View Transitions: The Gotchas Nobody Mentions | CSS-Tricks What’s !important #11: 3D Voxel Scenes, Flying Focus, CSS Syntaxes, and More | CSS-Tricks Computing and Displaying Discounted Prices in CSS | CSS-Tricks rotateX() | CSS-Tricks rotateY() | CSS-Tricks rotateZ() | CSS-Tricks rotate() | CSS-Tricks Soon We Can Finally Banish JavaScript to the ShadowRealm | CSS-Tricks contrast() | CSS-Tricks contrast-color() | CSS-Tricks hypot() | CSS-Tricks saturate() | CSS-Tricks justify-self | CSS-Tricks
Using CSS corner-shape For Folded Corners | CSS-Tricks
Daniel Schwarz · 2026-05-08 · via CSS-Tricks

I came across Kitty Giraudel’s folded corners technique. It leverages CSS clip-path, and I thought that that was such a cool way to do it. clip-path has been trending lately, most likely because web browsers support the shape() function now.

However, I’ve been on a bit of a corner-shape kick lately (have a look at my introduction to corner-shape as well as these scroll-driven corner-shape animations), so I figured that corner-shape could be used to create folded corners as well, and this is what I came up with:

White paper with the top-right corner folded in.

So open Chrome, which supports corner-shape, and let’s dig in (if you’re looking at this in other browsers, it basically falls back to a rounded corner).

Step 1: Set some CSS variables

Elements have four corners, but when we use border-radius, each corner is split into two coordinates. The x-axis coordinate moves along the x-axis, away from its associated corner, while the y-axis coordinate does the same thing along the y-axis. It’s from these coordinates that border-radius draws the curvature of the rounded corners.

Diagramming the shape showing border-radius applied to the bottom-left corner. The rounded corner is 50% on the y-axis and 50% on the x-axis.

First, store the coordinates as CSS variables. We’ll need the values that they hold more than once, so this simplifies things, makes the fold animatable, and maintains some degree of realism.

:root {
  /* x-axis coordinate */
  --x-coord: 9rem;

  /* y-axis coordinate */
  --y-coord: 5rem;
}

Step 2: Establishing the fold

Given what we now know about border-radius, it should be obvious what border-top-right-radius does. As for corner-top-right-shape: bevel, that ensures that a straight line is drawn between the coordinates instead of rounded corners (corner-top-right-shape: round). That’s right, border-radius includes corner-shape: round by default (behind the scenes, of course).

/* Square */
div {
  /* Place coordinates */
  border-top-right-radius: var(--x-coord) var(--y-coord);

  /* Draw line between coordinates */
  corner-top-right-shape: bevel;
}
White paper with a diagonal cut in the top-right corner.

Step 3: Creating the flip side

Now that we’ve established the fold, it’s time to create the flip side. Start by selecting ::before, then declare content: "" to create the element without content. The background can be inherited from the square, and the dimensions should leverage the coordinates that we saved. As you can see, I’ve also added a box-shadow where the blur radius scales with --x-coord and --y-coord, but you’re welcome to adapt the formula as you see fit.

/* Square */
div {
  /* Place coordinates */
  border-top-right-radius: var(--x-coord) var(--y-coord);

  /* Draw line between coordinates */
  corner-top-right-shape: bevel;

  /* Flip side */
  &::before {
    /* Generate empty element */
    content: "";

    /* Inherit background */
    background: inherit;

    /* Same as coordinates */
    width: var(--x-coord);
    height: 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;
  }
}
White paper with s white rectangle in the top-left corner and a diagonal cut in the top-right corner.

Step 4: Positioning the flip side (::before)

Next, we need to shift ::before to the (top-)right corner. We’re avoiding anchor positioning, because there’s no need for modern features if more supported features work well using the same amount of code. So, declare position: relative on the square and position: absolute on ::before. This makes ::before position relative to the square, and is a trick that only works for parent-child relationships. Actually, this shortcoming is why anchor positioning was invented, but we just don’t need it in this case.

In addition, declare inset: 0 0 auto auto on ::before to align it to the top-right corner of the square, and overflow: clip on the square to clip the half of ::before that overflows it.

/* Square */
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 */
  position: relative;

  /* Flip side */
  &::before {
    /* Generate empty element */
    content: "";

    /* Inherit background */
    background: inherit;

    /* Same as coordinates */
    width: var(--x-coord);
    height: 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 */
    position: absolute;

    /* Align to top-right */
    inset: 0 0 auto auto;
  }
}
White paper with the top-right corner folded in.

You can stop here if you want, but there’s room for improvement…

Step 5: Sculpting the flip side

To make the outcome look a bit more realistic, we’ll use corner-bottom-left-shape: bevel to make one more straight cut, this time to ::before. There are, most likely, many ways to tackle this depending on how sharply we want to crease the fold, how elevated we want the flip side to be, and the angle from which we want to view the square, but I don’t think it matters as long as the effect looks decent, so we’re aiming for a sharp crease, the flip side sticking up, and an aerial view. If you’d rather something different, keep in mind that the shadow also impacts the outcome, and that you’d be facing a trickier implementation.

The only degree of complexity that I suggest is this:

/* Ensure realistic fold */
@container style(--x-coord < --y-coord) {
  border-bottom-left-radius: 100% calc(100% - var(--x-coord));
}

@container style(--x-coord >= --y-coord) {
  border-bottom-left-radius: calc(100% - var(--y-coord)) 100%;
}

These are container style queries using the range syntax, where if the value of --x-coord is less than the value of --y-coord, we subtract the value of --x-coord from 100% and use it as the y-axis coordinate for the relevant border radius (border-bottom-left-radius, in this case). The other axis is set to 100%. Adversely, if the value of --x-coord is more than (or equal to) the value of --y-coord, we subtract the value of --y-coord from 100% and use it as the x-axis coordinate. Once again, the other axis is set to 100%.

The result is that the crease, shadow, and now perspective of the fold is calculated using only --x-coord and --y-coord to look realistic (or realistic enough, anyway). Using the slideVars toggles in the top-right corner of the demo, you can see for yourself by testing various combinations of coordinates:

If you want to implement a failsafe to ensure that the coordinates don’t exceed the dimensions of the square, breaking the effect, you can use min(). The modified coordinate variables below set --y-coord to an impossible 999999999rem, but caps it at the height of the square (although I can’t imagine that you’d actually need this, to be completely honest):

--x-coord: min(--square-width, 9rem);
--y-coord: min(--square-height, 999999999rem);
White paper with the top-right corner folded in.

All in all, we have not only a folded corner effect but a utility that builds the effect based on only two coordinates.

The full code:

:root {
  /* x-axis coordinate */
  --x-coord: 9rem;

  /* y-axis coordinate */
  --y-coord: 5rem;

  /* Square */
  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 */
    position: relative;

    /* Flip side */
    &::before {
      /* Generate empty element */
      content: "";

      /* Inherit background */
      background: inherit;

      /* Same as coordinates */
      width: var(--x-coord);
      height: 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 */
      position: absolute;

      /* Align to top-right */
      inset: 0 0 auto auto;

      /* Draw line between coordinates */
      corner-bottom-left-shape: bevel;

      /* Ensure realistic fold */
      @container style(--x-coord < --y-coord) {
        border-bottom-left-radius: 100% calc(100% - var(--x-coord));
      }

      @container style(--x-coord >= --y-coord) {
        border-bottom-left-radius: calc(100% - var(--y-coord)) 100%;
      }
    }
  }
}

Note: We could swap container style queries for if() functions, which are shorter but less readable.

Folded corners using clip-path vs. corner-shape

Kitty’s Giraudel’s folded corners work in all browsers, and because clip-path is used, which is a more versatile shaping feature, there are more ways to customize the shape. It’s also the more correct approach, for whatever that’s worth. However, my corner-shape approach is cleaner and likely wouldn’t require any further customization anyway, but lacks Safari and Firefox support for now. So unless you need folded corners today, I’d bookmark both: