Skip to content

Commit 85e0ca0

Browse files
noamrtabatkins
andauthored
[css-borders-4] Specify corner-shape based on superellipse (#11606)
* [css-borders-4] Specify `corner-shape` based on superellipse 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 #10993 Based on resolution #10993 (comment) Co-authored-by: Tab Atkins Jr.
1 parent 947cd87 commit 85e0ca0

File tree

1 file changed

+155
-43
lines changed

1 file changed

+155
-43
lines changed

css-borders-4/Overview.bs

Lines changed: 155 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -336,29 +336,168 @@ The 'border-radius' shorthand
336336
See [[CSS3BG]].
337337

338338

339-
Corner Shaping: the 'corner-shape' property
339+
Corner Shaping
340+
341+
By default, non-zero border-radii define a quarter-ellipse that rounds the affected corners.
342+
However in some cases, other corner shapes are desired.
343+
The 'corner-shape' property group specifies a reinterpretation of the radii to define other corner shapes.
344+
345+
The different shapes applicable to 'corner-shape' can be expressed as different parameters to a superellipse.
346+
A superellipse is a closed curve resembling an ellipse, and based on its `k` parameter can express all the shapes between a square, an ellipse, and a notch.
347+
348+
To allow full expression as well as interpolation, the 'corner-shape' properties can provide its own superellipse parameter using the 'superellipse()' function,
349+
or use one of the supplied keywords which represent commonly used parameters. See the <> definition for details.
350+
351+

352+
Rendering 'corner-shape'
353+
'corner-shape' works alongside 'border-radius', and does not have any visual effect with a 'border-radius' of 0.
354+
It acts as an alteration on top of the default round 'border-radius', and thus can be used as progressive enhancement.
355+
356+
Like 'border-radius', 'corner-shape' clips elements according to the [=overflow=] rules, and applies to the rendering of the border.
357+
Since stroking a superellipse accurately may be computationally intensive, user agents may approximate the path using bezier curves,
358+
as well as account for sharp edges and overlaps.
359+
360+
Issue: 'border-radius' already handles *adjacent* corners overlapping by shrinking the radiuses proportionally.
361+
A negative ''superellipse()'' parameter allows for *opposite* corners to sometimes overlap, and needs additional restrictions defined.
362+
363+
Issue #11610: check if we need additional rendering restrictions.
364+
365+

366+
'corner-shape' values
367+
368+
369+
<> = ''round'' | ''scoop'' | ''bevel'' | ''notch'' | ''straight'' | ''squircle'' | superellipse(<>)
370+
371+
372+
373+
round
374+
375+
Border radii define a convex elliptical curve at the corner. Equivalent to superellipse(2).
376+
377+
Note: this is the initial value of 'corner-shape' properties, as elements with 'border-radius' would be rounded.
378+
379+
scoop
380+
Border radii define a concave elliptical curve at the corner. Equivalent to superellipse(0.5).
381+
bevel
382+
Border radii define a diagonal slice at the corner. Equivalent to superellipse(1).
383+
notch
384+
Border radii define a concave 90deg angle at the corner. Equivalent to superellipse(0).
385+
straight
386+
Border radii define a convex 90deg angle at the corner.
387+
This would have the same visual effect as a 'border-radius' of 0. This is different from having a 'border-radius' of 0 when animating.
388+
Equivalent to superellipse(infinity).
389+
squircle
390+
Border radii define a convex curve between an ellipse and an convex angle, equivalent to superellipse(4).
391+
392+
393+
Issue #11607: resolve on ''straight'' vs none.
394+
395+
The superellipse( <> | infinity ) function describes the curvature of the corner.
396+
It accepts a superellipse exponent, which defines the curvature of the corner, or the exponent of the formula.
397+
The [=superellipse exponent=] accepts values between 0 (a straight concave angle) and infinity (a straight convex angle),
398+
with the values in between representing the curvatures in between.
399+
400+
The ''superellipse()'' formula can be described in cartesian coordinates, as follows,
401+
where a is the horizontal ''border-radius''
402+
b is the vertical ''border-radius'', and k is the [=superellipse exponent=]:
403+
404+
405+
|x/a|^k + |y/b|^k = 1
406+
407+
408+

409+
Corner Shaping: the 'corner-shape' and 'corner-*-shape' properties
340410

341411
342412
Name: corner-shape
343-
Value: [ round | angle ]{1,4}
413+
Value: <>{1,2} / [ <>{1,2} ]?
344414
Initial: round
345-
Applies to: all elements, except table element when 'border-collapse' is ''collapse''
415+
Applies to: all elements where 'border-radius' can apply
346416
Inherited: no
347-
Animation type: discrete
417+
Animation type: see individual properties
348418
349419

350-
By default, non-zero border-radii define
351-
a quarter-ellipse that rounds the affected corners.
352-
However in some cases, other corner shapes are desired.
353-
The 'corner-shape' property specifies a reinterpretation of the radii
354-
to define other corner shapes.
355-
356-
357-
''round''
358-
Border radii define a convex elliptical curve at the corner.
359-
''angle''
360-
Border radii define a diagonal slice at the corner.
361-
420+
Applies the shape to all corners, following the same rules as ''border-radius''.
421+
422+
423+
Name: corner-top-left-shape, corner-top-right-shape, corner-bottom-right-shape, corner-bottom-left-shape, corner-start-start-shape, corner-start-end-shape, corner-end-start-shape, corner-end-end-shape
424+
Value: <>
425+
Initial: round
426+
Applies to: all elements where 'border-radius' can apply
427+
Inherited: no
428+
Logical property group: corner-shape
429+
Computed value: the corresponding ''superellipse()'' value
430+
Animation Type: see [=superellipse interpolation=]
431+
432+
433+
The [=flow-relative=] properties
434+
'corner-start-start-shape',
435+
'corner-start-end-shape',
436+
'corner-end-start-shape',
437+
and 'corner-end-end-shape'
438+
correspond to the [=physical=] properties
439+
'corner-top-left-shape',
440+
'corner-bottom-left-shape',
441+
'corner-top-right-shape',
442+
and 'corner-bottom-right-shape'.
443+
The mapping depends on the element’s 'writing-mode', 'direction', and 'text-orientation',
444+
with the first start/end giving the block axis side,
445+
and the second the inline-axis side
446+
(i.e. patterned as 'corner-block-inline-shape').
447+
448+
449+
Name: corner-top-shape, corner-right-shape, corner-bottom-shape, corner-left-shape,
450+
corner-block-start-shape, corner-block-end-shape, corner-inline-start-shape, corner-inline-end-shape
451+
Value: <> [ / <> ]
452+
Initial: round
453+
Applies to: all elements where 'border-radius' can apply
454+
Inherited: no
455+
Computed value: see individual properties
456+
Animation type: see individual properties
457+
458+
459+

The 'corner-*-shape' shorthands set the two 'corner-*-*-shape'

460+
longhand properties of the related side. If values are given before
461+
and after the slash, then the values before the slash set the
462+
horizontal radius and the values after the slash set the vertical radius.
463+
If there is no slash, then the values set both radii equally.
464+
The two values for the radii are given in the order
465+
top-left, top-right for 'corner-top-shape',
466+
top-right, bottom-right for 'corner-right-shape',
467+
bottom-left, bottom-right for 'corner-bottom-shape',
468+
top-left, bottom-left for 'corner-left-shape',
469+
start-start, start-end for 'corner-block-start-shape',
470+
end-start, end-end for 'corner-block-end-shape'
471+
start-start, end-start for 'corner-inline-start-shape',
472+
and start-end, end-end for 'corner-inline-end-shape'.
473+
If the second value is omitted it is copied from the first.
474+
475+
476+

477+
Interpolating corner shapes
478+
479+
Since a <> can always be expressed by a ''superellipse()'' with an [=superellipse exponent=] variable, interpolating between two
480+
<>s is done by interpolating the [=superellipse exponent=] itself.
481+
Since it's an exponent, interpolating it linearly would result in an effect where concave corners interpolate at a much higher velocity than convex corners.
482+
To balance that, the superellipse interpolation formula describes how a [=superellipse exponent=] is converted to a value between 0 and 1, and vice versa:
483+
484+
485+
To interpolate a <> |exponent| to an interpolation value between 0 and 1:
486+
1. If |exponent| is 0, return 0.
487+
1. If |exponent| is ∞, return 1.
488+
1. Return 1/(2^(1/|exponent|)).
489+
490+
To convert a <> |interpolationValue| back to a [=superellipse exponent=]:
491+
1. If |interpolationValue| is 0, return 0.
492+
1. If |interpolationValue| is 1, return ∞.
493+
1. Return ln(0.5)/ln(|interpolationValue|).
494+
495+
496+
Issue #11608: resolve on this or another interpolation formula.
497+
498+
499+
500+
362501

363502
364503
For example, the following declarations create a right-pointing next button.
@@ -398,33 +537,6 @@ Corner Shaping: the 'corner-shape' property
398537
How to allow custom corners? Perhaps a ''path()'' function? Or a ''cubic-bezier()''?
399538
Something else?
400539

401-

402-
Corner Shape and Size: the 'corners' shorthand
403-
404-
405-
Name: corners
406-
Value: <<'corner-shape'>> || <<'border-radius'>>
407-
408-
409-
The 'corners' shorthand sets 'corner-shape' and 'border-radius' in the same declaration.
410-
If either is omitted, it is reset to its initial value.
411-
412-
413-
For example, the following declaration creates a diamond shape.
414-
corners: angle 50%;
415-
In UAs that don't support 'corner-shape', the declaration is ignored
416-
(falls back to a rectangle).
417-
418-
419-
420-
In this example, the first declaration creates tabs with vertical sides and rounded corners using 'border-radius',
421-
while the second example makes them trapezoid-shaped in UAs that support 'corners'.
422-
423-
border-radius: 0.25em 0.25em 0 0;
424-
corners: angle 0.25em 0.25em 0 0 / 50% 50% 0 0;
425-
426-
427-
428540

429541
Partial borders
430542

0 commit comments

Comments
 (0)