-
Notifications
You must be signed in to change notification settings - Fork 689
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
[css-shapes-2][css-borders-4] corner-shape support for superellipses #10993
Comments
pinging some folks that talked to me about this at some point @tabatkins @fantasai @smfr @vmpstr @LeaVerou @stubbornella @progers |
I quite like this! The fact that it directly handles straight lines (bevel), round corners, squircles, and square corners (and the inversions of all of them; scoop and notch) is great; it also gives us an unexpected new ability to animate between these shapes, which kinda rules. I don't think it's a problem that the function takes numerical value with "magic numbers". That's just a result of making anything parametrized. The fact that all the "meaningful" behaviors (those common enough to be granted names) are the integer values 0, ±1, and ±2, and ±∞ means, imo, that the argument is meaningful enough. I definitely agree with log-rescaling the parameter. It makes the function substantially easier to use and understand, with amazing symmetry (positive and negative values are the exact same shape, just convex or concave). It also makes "large enough to look square" a much more achievable value, and thus much friendlier to animation; going from Quick note about animation - I suspect we want to have keywords compute to themselves, but convert to an equivalent And yeah, as you mention (and is also mentioned by Simon and me in #8591 (comment)), we'll need to define how concave corners (negative Unfortunately I do not have a better name suggestion. However, maybe we can simply avoid the issue entirely, and just represent it as a naked |
I really like this. Just one check, following up on a discussion we had at TPAC: does this formulation deal well with "/" version of |
I think you're asking if superellipses support an elliptical corner (different absolute lengths for x and y radius)? If so, yes, it's a superellipse after all. ^_^ |
Okay, I know I said I no longer think |
|
How is that the opposite? It sounds like exactly the same? 🤔 |
Tab says to convert keywords to equivalent numeric only for interpolation. |
I see that the demo has an iterative approach to rendering the superelljpse corners. It would be great if we could somehow compute beziers to avoid having to render paths with thousands of points. |
I've compared the squircle rendering using the superellipse function with the Apple native "continuous rounded rects", and they are different enough that I question whether web devs won't find the native continuous rounded rects more appealing. Here's a zoomed-in view of the difference (for The superellipse still has the property that there is a sharp corner between the flat edge and the start of the curve, which is the primary reason people want squircles. This is much smoother with continuous rounded rects. The continuous rounded rect is a Bézier curve with four points per corner: (this is not quite to scale relative to the first image). Something to note is that continuous rounded rects affect the "flat" part of the edges; their influence on the flat sides extents about 1.5x of the corner radius. That means that it's tricky to convert them to a circle for |
I guess that's only true if you don't use |
Here's an interesting article on Figma's investigation into squircles (where they are trying to match the Apple type of squircle). |
Just as a thought, perhaps in addition to a squircle-specific thing, we can allow cartesian functions in shapes, and then superellipses can be expressed using custom functions, and we can perhaps ship some built-in stock custom functions? @function --superellipse(--rx, --ry, --n, --x) {
result: calc(var(--ry) * pow(1 - pow( var(--x) / var(--rx), var(--n)), 1 / var(--n)));
}
@function --squircle-arc(--x) {
result: --superellipse(50%, 50%, 3, --x);
}
.squircle {
clip-path: shape(from 50% 0,
plot --squircle-arc to 100% 50%,
plot --squircle-arc to 50% 100%,
plot --squircle-arc to 0 50%,
plot --squircle-arc to 50% 0
);
} This way if someone wants a "slightly different" arc we don't have to convene again to decide on specifics :) |
Should this and #6296 be merged? I want to consolidate the squircle/superellipsis discussion. |
@smfr is the formula for Swift-style continuous rounded rect public somewhere? Seems like something designers were looking for for a long time and has a bit of secrecy around it, e.g. that Figma blog post. |
Uploaded a playground where we can all play with the different options: https://noamr.github.io/squircle-testbed/ |
To move this forward, I think this should be a property like in the OP, but perhaps So something like: corner-smoothing: normal | squircle | superellipse(exp) | continuous Where |
@noamr Is the “Continuous Rounded” in this demo the same formula as Swift's Indeed, we need Apple-style |
@smfr I think if
So are the rounded corners in Figma's article consistent with Swift? |
Yes, as per @smfr.
Still wondering if that's what the bulk of the industry thinks, or if some people want continuous rounded rects and some want squircles/superellipses for different types of designs, and whether CSS should be opinionated about this. |
The CSS Working Group just discussed The full IRC log of that discussion<emilio> smfr: there's a proposal to add a squircle function / different types of corner treatments<emilio> ... there's also bevels / etc <emilio> ... but more recently there's been a proposal of `superellipse` function <emilio> ... which would allow those and also things in between <emilio> ... including squircle <emilio> ... wanted to give some background and some reservations I have about it <emilio> ... this demo is using border-radius <emilio> ... this is existing border-radius <noamr> https://noamr.github.io/squircle-testbed/ <emilio> ... the "Apple rounded rect" is also a regular bezier point but with more control points <emilio> ... There's some tricky cases with overlapping corners <emilio> ... superellipse is this function that for a k=0 gets you bevel, with different ks you can get different joins <emilio> ... with different ks you can get something like the squircle <emilio> ... but now you got multiple parameters to change <emilio> ... border-radius and the k <emilio> ... it's not clear for authors which combination they'd choose <TabAtkins> q+ <emilio> ... The other thing is that it's generated iteratively <astearns> zakim, open queue <Zakim> ok, astearns, the speaker queue is open <TabAtkins> q+ <noamr> q+ <emilio> ... not using bezier curves, so not very efficient to render unless you approximate it using bezier curves <astearns> ack noamr <emilio> noamr: The proposal was also to add a squircle keyboard <emilio> ... agreed with the perf concern <emilio> ... specially stroking, filing should be fine with shaders <emilio> ... for that reason I'm more inclined towards the apple-style continuous rect rather than superellipse <astearns> ack TabAtkins <emilio> ... on the other side I'd like more expresiveness for authors if we can solve the efficiency problem <emilio> TabAtkins: in your later comments you said that to do a squircle you'd need both k and border-radius <emilio> ... how does that work with just a squircle corner shape <emilio> ... presumably the flat segment is specified by border radius <emilio> smfr: yeah we apply the squircle only to the rounded corner area <emilio> TabAtkins: ok so this is a different curve than superellipse <weinig> q+ <emilio> TabAtkins: so in your preferred solution you have a small border radius with a separate knob <emilio> smfr: right <florian> q+ <emilio> TabAtkins: so this seems to be two parameters as well right? <emilio> smfr: Only one parameter, which is border-radius <emilio> TabAtkins: is it just because the squircle is a fixed pos? <emilio> smfr: pretty much <emilio> TabAtkins: it seems for fserb's proposal the squircle thing would just be a fixed k=4 right? So seems similar? <emilio> ... so if you're using the fixed squircle shape you have only one free parameter <emilio> ... the computational issues are a thing, but the parameterization seems fine to me? <emilio> smfr: depends on how we want to expose this to CSS <emilio> ... so adding squircle / bevel with keywords or something more flexible <emilio> TabAtkins: I think fserb's proposal was to add keywords that computed to the superellipse parameters <emilio> ... but I don't understand the calculus of the different params here <emilio> ... so that might trump it <astearns> ack weinig <emilio> weinig: Is there any standardization in the design community outside apple / google that we could use here? <emilio> smfr: I think there's a figma thing where they were looking at the apple one, but depends on which camp we're on <emilio> weinig: Is there a built-in superellipse in illustrator on something? <emilio> s/on/or <emilio> smfr: not sure illustrator but figma and so do <emilio> ... there's also the question of what authors want, just apple/google squircle or something else <emilio> weinig: I don't think we want to hardcode the apple one, it could change in the future or what not <emilio> smfr: I agree we don't want a single keyword that just gives you exactly the apple one <emilio> ... we're fine with authors having to tweak border-radius or what not <schenney> q+ <emilio> smfr: For IP reasons we don't want a single keyword that gives you the apple shape, but we're fine giving the corner treatment <emilio> weinig: that makes sense, was trying to see what the non-app-icon use from authors would be generally useful <noamr> q+ <emilio> smfr: And agree on let's not lock in on the current rounded icon format <astearns> ack florian <emilio> florian: what I like about fserb's proposal is that it gives keywords for things authors really want, and an underlying system <emilio> ... to explore other bits <emilio> ... not in a position to talk about performance, but I hope it can be fixed <emilio> ... there are more knobs that your demo doesn't show (like each corner separately) <astearns> ack schenney <emilio> schenney: wanted to point out that animation is not being discussed yet, but an animation would lean towards a functional notation <florian> s/like each corner separately/like each corner separately, or each side of each corner… <emilio> smfr: agree, I think it's going to be possible to approximate superellipses with beziers <kizu> q+ <emilio> ... I think it's tractable. Certainly more convenient with the k param <astearns> ack noamr <TabAtkins> q+ <emilio> noamr: From the perspective of how to bring this to the masses, I'd suggest to start with the continuous one and then build on top <emilio> ... then try to figure out approximation of superellipse or what not <emilio> ... thoughts? <emilio> smfr: I agree we could do keywords first <emilio> ... we'd have to think about animations <emilio> ... maybe just discrete for now <emilio> kizu: +1 to florian <astearns> ack kizu <kizu> https://github.com//issues/6980 <emilio> ... both the superellipsis and a set of keywords <weinig> (likely the blog post from Figma smfr mentioned -> https://www.figma.com/blog/desperately-seeking-squircles/ ) <emilio> ... issue above has lots of comments about that <florian> q+ to ask how bad is the performance problem <astearns> ack TabAtkins <emilio> ... so yeah would be good to have the functional version to create something more interesting <emilio> TabAtkins: if the idea is that a superellipse does get decent results but is computationally intractable <emilio> ... can we allow a degree of approximation in the spec so that you're allowed to approximate <emilio> ... I think that is not very controversial <emilio> ... so if beziers are tractable then we can just allow that <emilio> smfr: I think that's fine, I just haven't done the math to approximate the conversion yet <emilio> weinig: at the lower level most graphics libs are already doing approximations of these things <emilio> ... I think there's unlikely to be a sever penalty <emilio> TabAtkins: anything more rounded than a bevel needs an extra check for overlapping curves <emilio> smfr: Right, we already have some constraints on rounded rects <emilio> TabAtkins: right, but the border-radius overlap is trivial <schenney> q+ <emilio> smfr: Yeah for the simple case we can probably check the rects <emilio> ... maybe too restrictive <emilio> smfr: [draws something] <emilio> smfr: people want to do [that] <astearns> ack florian <Zakim> florian, you wanted to ask how bad is the performance problem <TabAtkins> example is: border-radius of 0 100% 0 100% <emilio> florian: unfortunate that fserb isn't here <noamr> q+ <emilio> ... curious, were you talking about approximating any k with bezier? <emilio> ... or just some k values? <emilio> ... if the former that's great <emilio> ... I think for superellipse() fserb had a reasonable implementation <astearns> ack schenney <emilio> smfr: Haven't tried generic k -> bezier conversion <emilio> schenney: it's not so much whether you can but how expensive the approximation is <emilio> ... even now with the existing rounded corners I'm 99% sure that there are still issues in browsers with border-width <emilio> ... so the interaction with border-width makes this trickier <emilio> ... certain border widths + radius cause this to be tricky, so would be good to consider it <emilio> smfr: agreed <astearns> ack noamr <emilio> noamr: we're not going to solve the computational issue in this meeting. Perhaps we should limit this to determine that we want the parametric superellipse() if achievable <emilio> ... have a rough CSS syntax for it and we can adjust based on implementability <emilio> astearns: was thinking of an even smaller step of starting with keywords, described in terms of superellipse <emilio> TabAtkins: that doesn't allow for smooth transitions in the future <smfr> q+ <emilio> astearns: if we're defining keywords in base of the superellipse, don't you get that? <emilio> TabAtkins: but the interpolation wouldn't be expressable until we get the function version <emilio> smfr: unless we do mix() function magic... <astearns> ack smfr <emilio> ... before resolving corner-shape, we probably want to decide whether we want border-shap <emilio> ... because they have interactive functionality <emilio> astearns: #6997? <emilio> smfr: yeah, would be nice to get leaverou's opinion about this too |
The CSS Working Group just discussed
The full IRC log of that discussion<emilio> PROPOSED: Add corner-shape with superellipsis() in some form<emilio> florian: [summarizes prev discussion for fserb] <emilio> fserb: is this because of how I implemented it on the demo or...? <emilio> smfr: q is whehter the iterative solution can be approximated to a bezier <emilio> fserb: I think so because you have the parameterized distance <emilio> ... can work on it a little bit <emilio> ... doesn't have to be as awful as in the demo <emilio> smfr: that sounds promising <emilio> PROPOSED: Add corner-shape with superellipsis() in some form, maybe keywords <emilio> noamr: maybe continuous to approx the apple curve <fserb> q+ <emilio> florian: unsure if that's needed given our discussion and k=4 being really close <emilio> smfr: do we have resolutions for bevel / scoop / etc? <emilio> astearns: we didn't resolve on anything yet <bramus> emilio: does not mean tha tif you add the keywords then add the function <bramus> florian: ?? compat problems <bramus> emilio: already ??? between discrete values <emilio> smfr: seems premature to add superellipse() if we don't have the basic keywords yet <noamr> +1 to starting with keywords <emilio> florian: but if you do it then you can't animate <astearns> ack fserb <emilio> emilio: but you'd be able to once you introduce the functional version <emilio> fserb: I think we should have both but it'd be weird to have only the keywords <noamr> any reason not to have both in the spec? <emilio> ... I think we should introduce the obvious keywords, but we should also have the superellipse() one <emilio> astearns: I think even if we only have those keywords we should define those in terms of superellipse() <emilio> fserb: unrelated, did we discuss about what happens about intersecting borders inside? <emilio> ... are we going to tweak border-width / radius to avoid it? <emilio> smfr: we decided we'd add constraints, but handwaved <bramus> emilio: should we propose that as a resolution? add restirctions to prevent some things. <fserb> +1 <emilio> florian: I'd prefer to add corner-shape: superellipse() + some keywords based on superellipse() <emilio> noamr: should we resolve on the specific keywords? <emilio> astearns: fine with editor discrection <astearns> ack fantasai <emilio> fantasai: there are keywords in the draft that map to this <emilio> astearns: can you list them? <emilio> smfr: probably bevel / scoop / notch / round? <bramus> emilio: is the initial value round? <bramus> … with this proposal we make it interact with border-radius <noamr> + squircle <fserb> scoop = -round ? <emilio> PROPOSAL: Add corner-shape: superellipse(k) and bevel / scoop / notch / round / squircle based on it, maybe continuous in the future <fserb> \o/ <emilio> RESOLVED: Add corner-shape: superellipse(k) and bevel / scoop / notch / round / squircle based on it, maybe continuous in the future <emilio> PROPOSED: Add restrictions to avoid intersecting borders with scoop-like borders <emilio> PROPOSED: Add restrictions to avoid intersecting borders with scoop-like corners, specifics TBD <emilio> RESOLVED: Add restrictions to avoid intersecting borders with scoop-like corners, specifics TBD <emilio> florian: current draft has angle rather than bevel <emilio> TabAtkins: editor discretion seems fine <emilio> [general agreement] <emilio> emilio: Initial value should be round so that border-radius does the right thing right? <bramus> emilio: can we define none in terms of superelipse? <emilio> noamr: maybe none for when there's nothing going on with the corners <bramus> smfr: yes <emilio> smfr: that's a bit different from animating radius <bramus> florian: are we also resolving that we have between 1 and 4 keywords and that they ??? a notch here and a rounded corner there <emilio> noamr: it'd be superellipse(calc(inf)) <bramus> …or do we worry about that later? <emilio> RESOLVED: Initial value of corner-shape is round <bramus> noamr: have corner-shape for corners spearately following model of border-radius <bramus> emilio: so corner-top-=left-shape and so on? <bramus> florian: same thing as border-radius <bramus> emilio: makes me sad that the prop deos not start with border- <bramus> florian: what makes me sad is that border-radius is not corner-radius <bramus> ntim: can add an alias <emilio> PROPOSED: corner-shape has longhands like border-radius <ntim> ntim: like we did for font-stretch/font-width <emilio> weinig: Spec has a corners shorthand, but no need to discuss it <emilio> RESOLVED: corner-shape has longhands like border-radius <jfkthame> present- |
This specifies the `corner-shape` group, including: - general description and interaction with border-radius - all the individual corners, side shorthands, and overall shorthand - multiple keywords, and how they translate to a `superellipse()` - The superellipse formula, and how it is rendered - How the exponent of the superellipse interpolates Open issues (will open separately): - Add a few examples - Resolve on "straight" vs "none" for the convex angle. - Resolve on the exact interpolation formula - Define restrictions for border rendering Closes w3c#10993 Based on resolution w3c#10993 (comment)
I worked a bit on trying to find an option for
corner-shape
on the new API that supported squircles and had inner/outer symmetry.After a bit of work I'm proposing we add a value
se(x)
(name TBD) that exposes a superellipse:Where$a$ and $b$ are the width and height of the shape. And the default parameter $n$ works in the interval $[0,\infty)$ where:
My proposal would be to use$x$ as a parameter where $n=2^x$ . This leads to a function that is symmetrical on $0$ where positive values are outside the bevel and negative values are inside, such as:
I've wrote a small demo with this function here.
The superellipse is very easily parameterizable (both angular and$[0,1]$ ), so I'm guessing it shouldn't be a problem to implement it in an efficient way. There's a small issue where if we are "inside the bevel" the corners can sometimes overlap. For those cases, we will have to do some math and limit the size of the corners to prevent it from happening (the demo currently doesn't handle those cases).
There are other available squircle formulations (like the Fernandez-Guasti squircles) where the parameter is more intuitive ($0$ means circle, $0.5$ is squircle, and $1$ is square). Unfortunately, those formulations don't extend to inwards the bevel, so we would lose some expressiveness.
We could, together with this, also provide certain easy-to-use values (like$[0,1]$ to $[1,\infty) $ ).
squircle
meaningse(2)
, orbevel
meaningse(0)
, etc...). And they could also contain parameters (i.e.squircle(y)
mappingHighlights:
Lowlights:
The text was updated successfully, but these errors were encountered: