Skip to content

[css-borders-4] Consider constraining radii for concave corner-shape when opposite corners overlap #12098

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
noamr opened this issue Apr 17, 2025 · 14 comments · Fixed by #12272
Closed

Comments

@noamr
Copy link
Collaborator

noamr commented Apr 17, 2025

The following CSS would cause the top-right and bottom-left corner to overlap, even without borders:

border-top-right-radius: 70%;
border-bottom-left-radius: 70%;
corner-shape: notch;

Basically anything more concave than this:
Image

would result in the corner collapsing on each other.

Since we constraint radius to not overlap in the ordinary round case, we should probably constraint it (or constraint the shape) in this case as well.

(Brought up by @smfr)

@SebastianZ
Copy link
Contributor

Sounds reasonable on first thought. Though avoiding overlapping also quickly becomes complex. Should borders also be accounted for? Should different shapes be handled differently (e.g. scoop vs. notch or round)? What about s vs. s as border radii? What about different values for horizontal and vertical radii?

Also, should there be an option to control this constraint? I assume there are use cases, for which overlapping is actually expected to achieve specific effects for split backgrounds. (Those might also be achievable via border-shape, though, depending on specifics in its definition.)

Sebastian

@noamr
Copy link
Collaborator Author

noamr commented Apr 21, 2025

Sounds reasonable on first thought. Though avoiding overlapping also quickly becomes complex. Should borders also be accounted for? Should different shapes be handled differently (e.g. scoop vs. notch or round)? What about s vs. s as border radii? What about different values for horizontal and vertical radii?

In a previous resolution we concluded on not considering borders here, only the outer contour. It simplifies things a lot.
Note that radii on the same axis are already constrained.

I think this is a question of whether we constrain the radii or the shape to not overlap diagonally in the outer contour. The rest would fall into place.

Also, should there be an option to control this constraint? I assume there are use cases, for which overlapping is actually expected to achieve specific effects for split backgrounds. (Those might also be achievable via border-shape, though, depending on specifics in its definition.)

Since we don't allow it for border-radius currently I think we should stick with that. The edge cases for overlapping borders are sufficiently edgy.

Sebastian

@smfr
Copy link
Contributor

smfr commented Apr 21, 2025

Overlapping brings up all kinds of complexities, like whether you're filling the border with an even-odd or non-zero wind rule. I think we have to avoid it.

@SebastianZ
Copy link
Contributor

Sounds reasonable on first thought. Though avoiding overlapping also quickly becomes complex. Should borders also be accounted for? Should different shapes be handled differently (e.g. scoop vs. notch or round)? What about s vs. s as border radii? What about different values for horizontal and vertical radii?

In a previous resolution we concluded on not considering borders here, only the outer contour. It simplifies things a lot.

I see! I obviously missed that resolution. So yes, that makes it much easier to handle.

Note that radii on the same axis are already constrained.

I know, but radii on the same axis are also relatively simple to handle.

I think this is a question of whether we constrain the radii or the shape to not overlap diagonally in the outer contour. The rest would fall into place.

Right.

Also, should there be an option to control this constraint? I assume there are use cases, for which overlapping is actually expected to achieve specific effects for split backgrounds. (Those might also be achievable via border-shape, though, depending on specifics in its definition.)

Since we don't allow it for border-radius currently I think we should stick with that. The edge cases for overlapping borders are sufficiently edgy.

Fair enough. If use cases for that come up at some point, we can still discuss it separately.

Overlapping brings up all kinds of complexities, like whether you're filling the border with an even-odd or non-zero wind rule. I think we have to avoid it.

Just to note, even if we don't allow overlapping for corner-shape + border-radius, we still need to solve that for border-shape.

Sebastian

@noamr
Copy link
Collaborator Author

noamr commented May 6, 2025

I actually thought of a third option that has some nice attributes to it: constraint the radius in only one of the dimensions.

For the following CSS:

border-top-right-radius: 70%;
border-bottom-left-radius: 70%;
corner-shape: notch;

where the radius in the next clockwise dimension remains unconstrained, and the radius in the counterclockwise dimension is constrained in such a way that the corners do not overlap. See options below for how this is going to look like.

This gives us 3 options. For each one I'll show what CSS it would be equivalent to and how the OP example would look like:

Original:

border-top-right-radius: 70%;
border-bottom-left-radius: 70%;
corner-shape: notch;
  1. Constrain the radius.
border-top-right-radius: 50%;
border-bottom-left-radius: 50%;
corner-shape: notch;

Image

  1. Constrain the shape
border-top-right-radius: 70%;
border-bottom-left-radius: 70%;
/* 1.02 is some computed number that puts the diagonal half corners in the same point */
corner-shape: superellipse(-1.02);

Image

  1. Constrain the radius in one dimension
border-top-right-radius: 50% 70%;
border-bottom-left-radius: 50% 70%;
corner-shape: notch;

Image

@tabatkins
Copy link
Member

When we're shrinking adjacent corners, we purposely shrink both radiuses, to keep the corner "shaped" the same. We also shrink both corners the same amount, just because there's no way to know which we should bias towards. I think we should do the same here.

That is, I think option 1 is the only reasonable option. Changing the superellipse parameter, or changing only one radius, both change the corner shape in dramatic ways, and I don't think either of those are acceptable outcomes.

@noamr
Copy link
Collaborator Author

noamr commented May 6, 2025

When we're shrinking adjacent corners, we purposely shrink both radiuses, to keep the corner "shaped" the same. We also shrink both corners the same amount, just because there's no way to know which we should bias towards. I think we should do the same here.

That is, I think option 1 is the only reasonable option. Changing the superellipse parameter, or changing only one radius, both change the corner shape in dramatic ways, and I don't think either of those are acceptable outcomes.

I am fine with this but would like to hear from others (@smfr / @SebastianZ / @LeaVerou / @fantasai ?).
If we get a rough consensus I'm happy to async resolve, or Agenda+ if we don't.

@LeaVerou
Copy link
Member

LeaVerou commented May 7, 2025

Happy to resolve to what @tabatkins proposed.

@smfr
Copy link
Contributor

smfr commented May 7, 2025

Agree that constraining the radii makes more sense than changing the shape. But how exactly does the constraining work? Does the superellipse value affect the amount of constraining? If one corner is notch, and the opposite corner is scoop, are they constrained equally? Do we constrain just enough such that the inner edge of the border touches (i.e. you never end up with two disjoint shapes as seen above)?

@noamr
Copy link
Collaborator Author

noamr commented May 8, 2025

Agree that constraining the radii makes more sense than changing the shape. But how exactly does the constraining work? Does the superellipse value affect the amount of constraining? If one corner is notch, and the opposite corner is scoop, are they constrained equally? Do we constrain just enough such that the inner edge of the border touches (i.e. you never end up with two disjoint shapes as seen above)?

A model we can follow is something as such:

  • We compute the hull for both corners
  • If the hulls don't intersect, do nothing
  • Find how many pixels the diagonal of each corner would have to shrink by independently in order for the hulls to touch but not intersect
  • Find the ratio between diagonals
  • Use the above to shrink the corners so that the ratio between the diagonals remains the same as before, but the hulls touch and don't intersect.
  • exact math TBD, but with hulls it's not too complex/costly.

@tabatkins
Copy link
Member

Yes, that sounds like a reasonable approach to me. I suspect there's a lot of potential flexibility in what exactly we do, but that algo seems straightforward and thematically consistent with how we shrink adjacent corners.

@noamr
Copy link
Collaborator Author

noamr commented May 12, 2025

Yes, that sounds like a reasonable approach to me. I suspect there's a lot of potential flexibility in what exactly we do, but that algo seems straightforward and thematically consistent with how we shrink adjacent corners.

@smfr does this seem reasonable to you?
The algorithm in the spec would be a bit high level, something like defining the "find a scale factor by which scaling both radii would make it so the quadrilateral hulls created by the shaped corners would touch but not intersect".

An implementation can use bsearch for this or find something more fancy/optimized.

@noamr
Copy link
Collaborator Author

noamr commented May 12, 2025

I've prototyped this: https://noamr.github.io/squircle-testbed/radii-constraint.html
(This works with the existing blink implementation of corner-shape, so requires Chrome Canary with experimental features turned on)

I think it looks quite reasonable.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-borders-4] Consider constraining radii for concave corner-shape when opposite corners overlap, and agreed to the following:

  • RESOLVED: Reduce all radii in order to avoid overlap of shapes
The full IRC log of that discussion noamr: Right now we constrain radius when there is a corner overalp
noamr: but we don't constrain for diagonals, because these can't overlap in convex shapes
noamr: but for concave shapes they can
noamr: so question is how do we constrain these?
noamr: Right now shrinking is all corners by a ratio
noamr: enough to avoid overlap of radii
noamr: Here I'm doing the same thing. If the shapes intersect, I shrink both so that they don't touch
noamr: Here proposal is in green
noamr: Both corners shrink by same ratio, and aspect ratios ar emaintained
"Hull" here is defined by the tangent at the center point intersecting the horizontal/vertical?
ack flackr
ack fantasai
fantasai: [missed] all the principles that led to the original conflict formula
fantasai: probably want to shrink all the radiuses, not just the two intersecting
fantasai: [missed more]
q+
ack TabAtkins
noamr: Keeps the shape, I like that
TabAtkins: but we don't do that with current case
TabAtkins: We don't do that for adjacent overlaps, so I"m not sure why we'd shrink everything in a diagonal overlap
q+
https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
fantasai: You reduce all of the radii
"When the sum of any two adjacent border radii exceeds the size of the border box, UAs must proportionally reduce the used values of all border radii until none of them overlap."
ALL radii
ack smfr
smfr: If you have convex and concave shapes, then you have some complex constraints
smfr: how do you do that
I'm wrong, fantasai is right, we do shirnk all of them
noamr: First constrain adjacent ones, then constrain the opposite ones
https://software.hixie.ch/utilities/js/live-dom-viewer/saved/13807
smfr: Maybe that works, yeah
q+
ack flackr
flackr: another possibility would be that we don't shrink and the border becomes a straight line
So we should shrink all of them, and jsut use the largest necessary factor between all four adjacent pairs and two diagonal pairs
q+
q+
noamr: wanted something consistent with adjacent borders
ack smfr
smfr: I don't think we should, the math is already super complicated
q-
TabAtkins: fantasai was right, we do shrink all of the corners if one pair is too large
TabAtkins: see demo ^
ack TabAtkins
TabAtkins: so we should be consistent, find the shrink factors necessary for all four adjacent corners and the diagonal corners ,and just apply the largest one to all the corners
fantasai: the reason we did it this way was to preserve the shape as much as possible. anything else distorts the shape
PROPOSED: Reduce all radii in order to avoid overlap
RESOLVED: Reduce all radii in order to avoid overlap of shapes

noamr added a commit to noamr/csswg-drafts that referenced this issue Jun 4, 2025
If the hulls of opposite corners overlap, find a scale factor that would prevent the overlap, and apply to all radii.

Resolution: w3c#12098 (comment)
Closes w3c#12098
tabatkins pushed a commit that referenced this issue Jun 4, 2025
* [css-borders-4] Constrain radii for concave opposite corners

If the hulls of opposite corners overlap, find a scale factor that would prevent the overlap, and apply to all radii.

Resolution: #12098 (comment)
Closes #12098

* Fix hull computation for convex/concave
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants