Skip to content

Commit 61108aa

Browse files
noamrtabatkins
andauthored
[css-borders-4] Apply corner-shape syntax resolutions (#12033)
* [css-borders-4] Apply corner-shape syntax resolutions - Use `square` instead of `straight` - Use the log2 version for the `superellipse()` parameter - Interpolate symetrically from the middle. Closes #11607 Closes #11608 Closes #11609 * Remove cruft * Fix math * small fix * small fix * nits * add note about symmetry * Add some example for rendering * Add figure * Update css-borders-4/Overview.bs * nits --------- Co-authored-by: Tab Atkins Jr. <jackalmage@gmail.com>
1 parent 943132e commit 61108aa

File tree

2 files changed

+83
-72
lines changed

2 files changed

+83
-72
lines changed

css-borders-4/Overview.bs

Lines changed: 82 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -367,45 +367,69 @@ Issue <a href="https://github.com/w3c/csswg-drafts/issues/11610">#11610</a>: che
367367
'corner-shape' values</h4>
368368

369369
<pre class=prod>
370-
<dfn><<corner-shape-value>></dfn> = <l>''round''</l> | <l>''scoop''</l> | <l>''bevel''</l> | <l>''notch''</l> | <l>''straight''</l> | <l>''squircle''</l> | superellipse(<<number [0,&infin;]>> | infinity)
370+
<dfn><<corner-shape-value>></dfn> = <l>''round''</l> | <l>''scoop''</l> | <l>''bevel''</l> | <l>''notch''</l> | <l>''<corner-shape-value>/square''</l> | <l>''squircle''</l> |
371+
superellipse(<<number [-&infin;,&infin;]>> | infinity | -infinity)
371372
</pre>
372373

373374
<dl dfn-type="value" dfn-for="<corner-shape-value>">
374375
<dt><dfn>round</dfn>
375376
<dd>
376-
Border radii define a convex elliptical curve at the corner. Equivalent to <css>superellipse(2)</css>.
377+
Border radii define a convex elliptical curve at the corner. Equivalent to <css>superellipse(1)</css>.
377378

378379
Note: this is the initial value of 'corner-shape' properties, as elements with 'border-radius' would be rounded.
379380

380381
<dt><dfn>scoop</dfn>
381-
<dd>Border radii define a concave elliptical curve at the corner. Equivalent to <css>superellipse(0.5)</css>.
382+
<dd>Border radii define a concave elliptical curve at the corner. Equivalent to <css>superellipse(-1)</css>.
382383
<dt><dfn>bevel</dfn>
383-
<dd>Border radii define a diagonal slice at the corner. Equivalent to <css>superellipse(1)</css>.
384+
<dd>Border radii define a diagonal slice at the corner. Equivalent to <css>superellipse(0)</css>.
384385
<dt><dfn>notch</dfn>
385-
<dd>Border radii define a concave 90deg angle at the corner. Equivalent to <css>superellipse(0)</css>.
386-
<dt><dfn>straight</dfn>
386+
<dd>Border radii define a concave 90deg angle at the corner. Equivalent to <css>superellipse(-infinity)</css>.
387+
<dt><dfn>square</dfn>
387388
<dd>Border radii define a convex 90deg angle at the corner.
388389
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.
389390
Equivalent to <css>superellipse(infinity)</css>.
390391
<dt><dfn>squircle</dfn>
391-
<dd>Border radii define a convex curve between an ellipse and an convex angle, equivalent to <css>superellipse(4)</css>.
392+
<dd>Border radii define a convex curve between an ellipse and an convex angle, equivalent to <css>superellipse(2)</css>.
392393
</dl>
393394

394-
Issue <a href="https://github.com/w3c/csswg-drafts/issues/11607">#11607</a>: resolve on ''straight'' vs <css>none</css>.
395+
The <dfn>superellipse( <<number>> | infinity | -infinity )</dfn> function describes the <dfn>superellipse parameter</dfn> of the corner.
396+
It is a number between <css>-infinity</css> and <css>infinity</css>, with <css>-infinity</css> corresponding to a straight concave corner,
397+
<css>infinity</css> corresponding to a square convex corner.
395398

396-
The <dfn>superellipse( <<number>> | infinity )</dfn> function describes the curvature of the corner.
397-
It accepts a <dfn>superellipse exponent</dfn>, which defines the curvature of the corner, or the exponent of the formula.
398-
The [=superellipse exponent=] accepts values between 0 (a straight concave angle) and <css>infinity</css> (a straight convex angle),
399-
with the values in between representing the curvatures in between.
400-
401-
The ''superellipse()'' formula can be described in cartesian coordinates, as follows,
402-
where <code>a</code> is the horizontal ''border-radius''
403-
<code>b</code> is the vertical ''border-radius'', and <code>k</code> is the [=superellipse exponent=]:
399+
The <dfn>canonical superellipse formula</dfn> can be described in Cartesian coordinates, as follows,
400+
where <code>s</code> is the [=superellipse parameter=]:
404401

405402
<pre>
406-
|x/a|^k + |y/b|^k = 1
403+
k = 2<sup>abs(|s|)</sup>
404+
x<sup>k</sup> + y<sup>k</sup> = 1
407405
</pre>
408406

407+
The resulting |x| and |y| are later projected to CSS coordinates by scaling based on the 'border-radius' properties,
408+
inversed if the [=superellipse parameter=] is negative. This creates symmetry between convex and concave shapes of the same absolute
409+
[=superellipse parameter=].
410+
411+
<aside class=example>
412+
The ''<self-position>/start'' and ''<self-position>/end'' keywords
413+
are <a>flow-relative</a>:
414+
they use the <a>writing mode</a> to determine which side to align to.
415+
416+
<figure>
417+
<img src="images/superellipse-param.svg"
418+
width="320" height="240"
419+
style="background: white; padding: 8px;"
420+
title="rendering of different superellipse parameter values"
421+
alt="Rendering of different superellipse parameter values.">
422+
<figcaption>
423+
Rendering examples of different ''superellipse()'' values.
424+
</figcaption>
425+
</figure>
426+
</aside>
427+
428+
429+
<img src="images/superellipse-param.svg" alt="A diagram showing how superellipse values translate to curvature">
430+
431+
432+
409433
<h4 id=corner-shape-shorthand>
410434
Corner Shaping: the 'corner-shape' and 'corner-*-shape' properties</h4>
411435

@@ -474,66 +498,52 @@ Corner Shaping: the 'corner-shape' and 'corner-*-shape' properties</h4>
474498
<h4 id=corner-shape-interpolation>
475499
Interpolating corner shapes</h4>
476500

477-
Since a <<corner-shape-value>> can always be expressed by a ''superellipse()'' with an [=superellipse exponent=] variable, interpolating between two
478-
<<corner-shape-value>>s is done by interpolating the [=superellipse exponent=] itself.
479-
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.
480-
To balance that, the <dfn>superellipse interpolation</dfn> formula describes how a [=superellipse exponent=] is converted to a value between 0 and 1, and vice versa:
481-
482-
<div algorithm="superellipse-exponent-to-interpolation-value">
483-
To interpolate a <<number [0,&infin;]>> |exponent| to an interpolation value between 0 and 1:
484-
1. If |exponent| is 0, return 0.
485-
1. If |exponent| is &infin;, return 1.
486-
1. Return <code>1/(2^(1/|exponent|))</code>.
487-
488-
To convert a <<number [0,1]>> |interpolationValue| back to a [=superellipse exponent=]:
489-
1. If |interpolationValue| is 0, return 0.
490-
1. If |interpolationValue| is 1, return &infin;.
491-
1. Return <code>ln(0.5)/ln(|interpolationValue|)</code>.
492-
</div>
501+
Since a <<corner-shape-value>> can always be expressed by a ''superellipse()'' with an [=superellipse parameter=] variable, interpolating between two
502+
<<corner-shape-value>>s is done by interpolating the [=superellipse parameter=] itself.
503+
Since it uses a <code>log2</code>, interpolating it linearly would result in an effect where concave corners interpolate at a much higher velocity than convex corners.
504+
To balance that, the <dfn>superellipse interpolation</dfn> formula describes how a [=superellipse parameter=] is converted to a value between 0 and 1, and vice versa:
493505

494-
<a href="https://github.com/w3c/csswg-drafts/issues/11608">Issue #11608</a>: resolve on this or another interpolation formula.
506+
<div algorithm="superellipse-param-to-interpolation-value">
507+
To interpolate a <<number [-&infin;,&infin;]>> |s| to an interpolation value between 0 and 1, return the first matching statement, switch on |s|:
508+
<dl class=switch>
509+
: -&infin;
510+
:: Return 0.
495511

496-
<pre>
512+
: &infin;
513+
:: Return 1.
497514

498-
</pre>
515+
: Otherwise
516+
::
517+
1. Let |k| be <code>0.5<sup>abs(|s|)</sup></code>.
518+
1. Let |convexHalfCorner| be <code>0.5<sup>|k|</sup></code>.
519+
1. If |param| is less than 0, return <code>1 - |convexHalfCorner|</code>.
520+
1. Return |convexHalfCorner|.
499521

500-
<div class="example">
501-
For example, the following declarations create a right-pointing next button.
502-
<pre>
503-
a {
504-
border-radius: .3em .8em .8em .3em / .3em 50% 50% .3em;
505-
corner-shape: round angle angle round;
506-
padding: .5em 1em .5em .5em;
507-
}
508-
</pre>
509-
<div style='font: bold 200%/1 sans-serif;
510-
width: 2.3em;
511-
width: min-content;
512-
white-space: nowrap;
513-
padding: .5em 1.1em .5em .5em;
514-
border-radius: .3em 0 0 .3em;
515-
background: url(&apos;data:image/svg+xml,\
516-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 40">\
517-
<path d="m 0 0 h 65 l 10 20 l -10 20 h -65 z" fill="yellowgreen" />\
518-
</svg>&apos;) no-repeat 0 / auto 100%'>
519-
Next
520-
</div>
521-
As a fallback in UAs that don't support 'border-radius',
522-
the right side would be rounded rather than pointy:
523-
<div style='font: bold 200%/1 sans-serif;
524-
width: 2.3em;
525-
width: min-content;
526-
white-space: nowrap;
527-
padding: .5em 1em .5em .5em;
528-
border-radius: .3em .8em .8em .3em / .3em 50% 50% .3em;
529-
background: yellowgreen'>
530-
Next
531-
</div>
532-
</div>
522+
</dl>
533523

534-
<p class="issue">
535-
How to allow custom corners? Perhaps a ''path()'' function? Or a ''cubic-bezier()''?
536-
Something else?
524+
To convert a <<number [0,1]>> |interpolationValue| back to a [=superellipse parameter=], switch on |interpolationValue|:
525+
<dl class=switch>
526+
: 0
527+
:: Return -&infin;.
528+
529+
: 0.5
530+
:: Return 0.
531+
532+
: 1
533+
:: Return &infin;.
534+
535+
: Otherwise
536+
::
537+
1. Let |convexHalfCorner| be |interpolationValue|.
538+
1. If |interpolationValue| is less than 0.5, set |convexHalfCorner| to 1 - |interpolationValue|.
539+
1. Let |k| be <code>ln(0.5) / ln(|convexHalfCorner|)</code>.
540+
1. Let |s| be <code>log2(|k|)</code>.
541+
1. If |interpolationValue| is less than 0.5, return -|s|.
542+
1. Return |s|.
543+
544+
</dl>
545+
546+
</div>
537547

538548
<h2 id="partial-borders">
539549
Partial borders</h2>

0 commit comments

Comments
 (0)