- From: Noam Rosenthal via GitHub <noreply@w3.org>
- Date: Sun, 17 May 2026 18:34:47 +0000
- To: public-css-archive@w3.org
> Hm, I suppose you're right. It means custom machinery for this rather than reusing SVG machinery, but I suppose I don't know to what extent we _do_ reuse that machinery actually. And `path()` doesn't have the rounded-corner functionality, so at least we don't have to solve the general case; these are all sharp lines meeting at a corner. > > Okay, so the competing constraints we did border-radius under are: > > * in general, the inner corner reduces its radius by the spread, and the outer increases its radius by the spread > * except 0px radius needs to stay 0px when it expands, so we do a cubic interpolation between "stays the same" and "expands by the spread" based on the ratio of radius to border width; if the radius is larger than the border width (ratio > 1), it expands fully; if it's smaller, it expands less until it hits 0. > * except a _full radius_ (creating a circle or ellipse) should stay properly round (expanding the radius by the spread) regardless of the radius/border-width ratio, so we do a cubic interpolation between "apply the previous bullet point" and "ignore the previous bullet point" based on the ratio of radius to _box width/height_; if the radius is at least half the box's width or height (2*ratio > 1), it's fully ignored; if smaller, it applies the previous bullet point's correction in a scaling fashion. > > Here we have a general polygon. We use the border-width as the stroke width, meaning it both expands and contracts at each corner. This is already a break from border-radius behavior: a 1px border-radius with a 20px border width will have curve radiuses of 1px inner and 21px outer (curve defined for inner edge, expanded by 20px); a `round 1px` with a 2px border width will have curve radiuses of 0px inner and 11px outer (curve defined in center of border; both expanded and contracted by 10px). Do we want to change that to match perfectly? Or is it okay for that to be a little different, since if you want a border-radius rectangular border you can just _use border-radius_? (I lean toward the latter, so all the shapes work exactly the same, matching their equivalent polygon.) I think it's equivalent to having a regular shadow and an inset shadow. > > Going past the rect/inset/xywh functions, we calculate the rounding by positioning a circle of the given radius so that it's tangent to both line segments (possibly shrinking it if this would be more than half a segment's length). We then define the stroked path outlines by expanding and contracting the radius by half the border-width for the outer/inner edges of the corner, but also want the radius to stay 0 if it started as 0. > > Applying the first correction, to smoothly cubic-interpolate between "add the spread" and "do nothing", seems like a no-brainer. The only question would be whether it's better to compare the radius to the full border-width, or half the border-width (the actual spread amount); I somewhat lean toward the first one to match how 'border-radius' kicks in. It should be half the border-width. The inner stroke should act like an inset spread of that same half-stroke value. > The second correction is meant to handle people using border-radius to create circles/ellipses, which inclines me to say "just use `circle()`, that works correctly already", but it _also_ works for _pill_ shapes (full-face semicircular caps on a rectangle), which are definitely rounded rects with our current primitives. So I guess we do still need to do the same correction, and make it relative to how 2*radius compares with half the smaller segment length. Sounds right > > So, my initial conclusion: > > When determining the outer curve of a rect/polygon corner, expand the calculated radius by: > > ``` > (border-width/2) * (1 - (1 - ratio)³ * (1 - coverage³)) > // note the differing placements of the ³ operators > ``` > > where `ratio` is `radius / border-width` and coverage is `2 * radius / shorter-segment-length`; if either `ratio` or `coverage` is > 1, just use expand the radius by the full `border-width/2` as normal. > > The inner curve always contracts the radius by the `border-width/2`, floored at 0. - I think we *should* use 1/2 border with here but I need to see a visualisation of this - It's not about inner vs outer, but about expanding only the convex part. e.g. see https://codepen.io/editor/noamr-the-selector/pen/019e3733-018d-7154-b273-277778334462 (a similar thing exists for concave `corner-shape`). -- GitHub Notification of comment by noamr Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/13914#issuecomment-4472116465 using your GitHub account -- Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Sunday, 17 May 2026 18:34:48 UTC