Skip to content

Commit c03b2ea

Browse files
committed
[css-images-3] Pull in gradient midpoints from L4, per #1284. Also do significant editorial cleanup to match L4's incorportion of the new text, and generally improve things.
1 parent c1e4f53 commit c03b2ea

File tree

1 file changed

+208
-120
lines changed

1 file changed

+208
-120
lines changed

css-images-3/Overview.bs

Lines changed: 208 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ Gradients {#gradients}
174174

175175
A gradient is an image that smoothly fades from one color to another.
176176
These are commonly used for subtle shading in background images, buttons, and many other things.
177-
The gradient notations described in this section allow an author to specify such an image in a terse syntax,
177+
The <dfn export lt="gradient function">gradient functions</dfn> described in this section allow an author to specify such an image in a terse syntax,
178178
so that the UA can generate the image automatically when rendering the page.
179179
The syntax of a <<gradient>> is:
180180

@@ -766,93 +766,236 @@ Repeating Gradients: the ''repeating-linear-gradient()'' and ''repeating-radial-
766766
-->
767767

768768

769-
Gradient Color-Stops {#color-stop-syntax}
770-
-----------------------------------------
769+
Defining Gradient Color {#gradient-colors}
770+
-------------------------
771771

772-
<pre class=prod>
773-
<dfn>&lt;color-stop-list></dfn> = <<color-stop>>#{2,}
774-
<dfn>&lt;color-stop></dfn> = <<color>> <<length-percentage>>?
775-
</pre>
772+
The colors in gradients are specified using <dfn export lt="color stop">color stops</dfn>
773+
(a <<color>> and a corresponding position on the [=gradient line=])
774+
and <dfn export lt="color transition hint" local-lt="transition hint">color transition hints</dfn>
775+
(a position between two [=color stops=]
776+
representing the halfway point in the color transition)
777+
which are placed on the <a>gradient line</a>,
778+
defining the color at every point of the line.
779+
(Each [=gradient function=] defines the shape and length of the <a>gradient line</a>,
780+
along with its <a>starting point</a> and <a>ending point</a>;
781+
see above.)
782+
783+
<h4 id=color-stop-syntax>
784+
Color Stop Lists</h4>
776785

777-
The colors in gradients are specified using <a>color stops</a>.
778-
A <dfn export>color stop</dfn> is a combination of a color and a position.
779-
<!-- UNCOMMENT FOR L4
780-
Depending on the type of gradient, that position can be a length, angle, or percentage.
781-
-->
782-
While every color stop conceptually has a position,
783-
the position can be omitted in the syntax,
784-
in which case it gets automatically filled in by the user agent;
785-
see below for details.
786-
787-
The color stops for a gradient are specified
786+
787+
<a>Color stops</a> and [=transition hints=] are specified
788788
in a <dfn export>color stop list</dfn>,
789-
which is a list of two or more <a>color stops</a>,
790-
specified in geometric order.
789+
which is a list of two or more [=color stops=]
790+
interleaved with optional [=transition hints=]:
791791

792-
<a>Color stops</a> are placed on a <a>gradient line</a>,
793-
which defines the colors at every point of a gradient.
794-
The gradient function defines the shape and length of the <a>gradient line</a>,
795-
along with its <a>starting point</a> and <a>ending point</a>.
792+
<pre class=prod>
793+
<dfn>&lt;color-stop-list></dfn> =
794+
<<linear-color-stop>> , [ <<linear-color-hint>>? , <<linear-color-stop>> ]#
795+
<dfn>&lt;linear-color-stop></dfn> = <<color>> && <<length-percentage>>?
796+
<dfn>&lt;linear-color-hint></dfn> = <<length-percentage>>
797+
</pre>
796798

797-
Percentages refer to the length of the <a>gradient line</a>
799+
Percentages are resolved against the length of the <a>gradient line</a>
798800
between the <a>starting point</a> and <a>ending point</a>,
799801
with 0% being at the starting point
800802
and 100% being at the ending point.
801803
Lengths are measured along the <a>gradient line</a>
802804
from the <a>starting point</a>
803805
in the direction of the <a>ending point</a>.
804-
<!-- UNCOMMENT FOR L4
805-
Angles are measured with 0deg pointing up,
806-
and positive angles corresponding to clockwise rotations from there.
807-
-->
808806

809-
<a>Color stops</a> are usually placed between
807+
[=Color stop=] and [=transition hint=] positions
808+
are usually placed between
810809
the <a>starting point</a> and <a>ending point</a>,
811810
but that's not required:
812811
the gradient line extends infinitely in both directions,
813-
and a <a>color stop</a> can be placed at any position on the <a>gradient line</a>.
814-
815-
When the position of a <a>color stop</a> is omitted,
816-
it is positioned automatically
817-
halfway between the two surrounding stops.
812+
and positions can be specified anywhere
813+
on the <a>gradient line</a>.
814+
815+
When the position of a [=color stop=] is omitted,
816+
it is automatically assigned a position.
817+
The first or last [=color stop=] in the [=color stop list=]
818+
is assigned
819+
the [=gradient line’s=] [=starting point=] or [=ending point=]
820+
(respectively).
821+
Otherwise,
822+
it's assigned the position halfway between the two surrounding stops.
818823
If multiple stops in a row lack a position,
819-
they space themselves out equally.
820-
821-
The following steps must be applied <em>in order</em> to process the list of <a>color stops</a>.
822-
After applying these rules,
823-
all <a>color stops</a> will have a definite position and color
824-
and they will be in ascending order:
825-
826-
1. If the first <a>color stop</a> does not have a position,
827-
set its position to 0%.
828-
If the last <a>color stop</a> does not have a position,
829-
set its position to 100%.
824+
they space themselves out equally
825+
between the surrounding positioned stops.
826+
See [[#color-stop-fixup]] for details.
830827

831-
2. If a <a>color stop</a> has a position that is less than
832-
the specified position of any <a>color stop</a> before it in the list,
833-
set its position to be equal to the largest specified position of any <a>color stop</a> before it.
834828

835-
3. If any <a>color stop</a> still does not have a position,
836-
then, for each run of adjacent <a>color stops</a> without positions,
837-
set their positions so that they are evenly spaced between the preceding and following <a>color stops</a> with positions.
829+
<h4 id=coloring-gradient-line>
830+
Coloring the Gradient Line</h4>
838831

839832
At each <a>color stop</a> position,
840-
the line is the color of the <a>color stop</a>.
841-
Between two <a>color stops</a>,
842-
the line's color is linearly interpolated between the colors of the two <a>color stops</a>,
843-
with the interpolation taking place in premultiplied RGBA space.
833+
the [=gradient line=] is the color of the <a>color stop</a>.
844834
Before the first <a>color stop</a>,
845-
the line is the color of the first <a>color stop</a>.
846-
After the last <a>color stop</a>, the line is the color of the last <a>color stop</a>.
835+
the [=gradient line=] is the color of the first <a>color stop</a>,
836+
and after the last <a>color stop</a>,
837+
the [=gradient line=] is the color of the last <a>color stop</a>.
838+
Between two <a>color stops</a>,
839+
the [=gradient line’s=] color is interpolated between the colors of the two <a>color stops</a>,
840+
with the interpolation taking place in <a href="#premultiplied">premultiplied RGBA space</a>.
841+
842+
By default,
843+
this interpolation is linear--
844+
at 25%, 50%, or 75% of the distance between two <a>color stops</a>,
845+
the color is a 25%, 50%, or 75% blend of the colors of the two stops.
846+
847+
However, if a [=transition hint=] was provided between two <a>color stops</a>,
848+
the interpolation is non-linear,
849+
and controlled by the hint:
850+
851+
<div algorithm="interpolate with a color hint">
852+
<ol>
853+
<li>
854+
Determine the location of the [=transition hint=] as a percentage of the distance between the two <a>color stops</a>,
855+
denoted as a number between 0 and 1,
856+
where 0 indicates the hint is placed right on the first <a>color stop</a>,
857+
and 1 indicates the hint is placed right on the second <a>color stop</a>.
858+
Let this percentage be <var>H</var>.
859+
860+
<li>
861+
For any given point between the two color stops,
862+
determine the point's location as a percentage of the distance between the two <a>color stops</a>,
863+
in the same way as the previous step.
864+
Let this percentage be <var>P</var>.
865+
866+
<li>
867+
Let <var>C</var>, the color weighting at that point,
868+
be equal to <code><var>P</var><sup>log<sub><var>H</var></sub>(.5)</sup></code>.
869+
870+
<li>
871+
The color at that point is then a linear blend between the colors of the two <a>color stops</a>,
872+
blending <code>(1 - <var>C</var>)</code> of the first stop and <var>C</var> of the second stop.
873+
</ol>
874+
</div>
875+
876+
Note: The [=transition hint=] specifies where the “halfway color”--
877+
the 50% blend between the colors of the two surrounding color stops--
878+
should be placed.
879+
When the hint is exactly halfway between the two surrounding color stops,
880+
the above interpolation algorithm
881+
happens to produce the ordinary linear interpolation.
882+
If the hint is placed anywhere else,
883+
it produces a smooth exponential curve
884+
between the surrounding color stops,
885+
with the “halfway color” occuring exactly where the hint specifies.
886+
887+
Issue: Add a visual example of a color hint being used.
847888

848889
If multiple <a>color stops</a> have the same position,
849-
they produce an infinitesimal transition from the one specified first in the rule
890+
they produce an infinitesimal transition from the one specified first in the list
850891
to the one specified last.
851892
In effect, the color suddenly changes at that position rather than smoothly transitioning.
852893

894+
<details class=note id=premultiplied>
895+
<summary>What does “pre-multiplied” mean?</summary>
896+
897+
A “pre-multiplied” color
898+
is written in a form
899+
where the alpha channel
900+
is multiplied into the color channels,
901+
rather than being processed independently.
902+
For example, a partially-transparent blue may be given as <code class=lang-css><nobr>rgba(0, 0, 255, .5)</nobr></code>,
903+
which would then be expressed as <code><nobr>[0, 0, 127.5, .5]</nobr></code> in its premultiplied representation.
904+
905+
Interpolating colors using the premultiplied representations
906+
rather than the plain rgba representations
907+
tends to produce more attractive transitions,
908+
particularly when transitioning from a fully opaque color to fully transparent.
909+
910+
Note that transitions where either the transparency or the color are held constant
911+
(for example, transitioning between <code class=lang-css><nobr>rgba(255, 0, 0, 100%)</nobr></code> (opaque red)
912+
and <code class=lang-css><nobr>rgba(0,0,255,100%)</nobr></code> (opaque blue),
913+
or <code class=lang-css><nobr>rgba(255,0,0,100%)</nobr></code> (opaque red)
914+
and <code class=lang-css><nobr>rgba(255,0,0,0%)</nobr></code> (transparent red))
915+
have identical results whether the color interpolation is done in premultiplied or non-premultiplied color-space.
916+
Differences only arise when <em>both</em> the color and transparency differ between the two endpoints.
917+
918+
<div class=example>
919+
The following example illustrates the difference between
920+
a gradient transitioning in pre-multiplied sRGBA
921+
and one transitioning (incorrectly) in non-premultiplied.
922+
In both of these example,
923+
the gradient is drawn over a white background.
924+
Both gradients could be written with the following value:
925+
926+
<pre>linear-gradient(90deg, red, transparent, blue)</pre>
927+
928+
With premultiplied colors,
929+
transitions to or from "transparent" always look nice:
930+
931+
<object data="images/gradient2.svg" width="200"height="100">(Image requires SVG)</object>
932+
933+
On the other hand,
934+
if a gradient were to incorrectly transition in non-premultiplied space,
935+
the center of the gradient would be a noticeably grayish color,
936+
because "transparent" is actually a shorthand for ''rgba(0,0,0,0)'', or transparent black,
937+
meaning that the red transitions to a black
938+
as it loses opacity,
939+
and similarly with the blue's transition:
940+
941+
<object data="images/gradient3.svg" width="200"height="100">(Image requires SVG)</object>
942+
</div>
943+
944+
</details>
945+
946+
947+
948+
<h4 id=color-stop-fixup>
949+
Color Stop “Fixup”</h4>
950+
951+
When resolving the [=used value|used=] positions of each [=color stop=],
952+
the following steps must be applied <em>in order</em>:
953+
954+
<ol>
955+
<li>
956+
If the first <a>color stop</a> does not have a position,
957+
set its position to 0%.
958+
If the last <a>color stop</a> does not have a position,
959+
set its position to 100%.
960+
961+
<li>
962+
If a <a>color stop</a> or [=transition hint=] has a position
963+
that is less than the specified position
964+
of any <a>color stop</a> or [=transition hint=] before it in the list,
965+
set its position to be equal to the largest specified position
966+
of any <a>color stop</a> or [=transition hint=] before it.
967+
968+
<li>
969+
If any <a>color stop</a> still does not have a position,
970+
then, for each run of adjacent <a>color stops</a> without positions,
971+
set their positions so that they are evenly spaced
972+
between the preceding and following <a>color stops</a> with positions.
973+
</ol>
974+
975+
After applying these rules,
976+
all [=color stops=] and [=transition hints=] will have a definite position and color
977+
and they will be in ascending order.
978+
979+
Note: It is recommended that authors exercise caution
980+
when mixing different types of units,
981+
such as px, em, or %,
982+
as this can cause a <a>color stop</a> to unintentionally try to move before an earlier one.
983+
For example,
984+
the rule ''background-image: linear-gradient(yellow 100px, blue 50%)''
985+
wouldn't trigger any fix-up while the background area is at least ''200px'' tall.
986+
If it was ''150px'' tall, however,
987+
the blue <a>color stop's</a> position would be equivalent to ''75px'',
988+
which precedes the yellow <a>color stop</a>,
989+
and would be corrected to a position of ''100px''.
990+
Additionally, since the relative ordering of such color stops
991+
cannot be determined without performing layout,
992+
they will not interpolate smoothly in
993+
<a href="http://www.w3.org/TR/css-animations/">animations</a>
994+
or <a href="http://www.w3.org/TR/css-transitions/">transitions</a>.
995+
853996
<div class=example>
854997
Below are several pairs of gradients.
855-
The latter of each pair is a manually "fixed-up" version of the former,
998+
The latter of each pair is a manually fixed-up version of the former,
856999
obtained by applying the above rules.
8571000
For each pair, both gradients will render identically.
8581001
<span class='note'>The numbers in each arrow specify which fixup steps are invoked in the transformation.</span>
@@ -863,86 +1006,31 @@ Gradient Color-Stops {#color-stop-syntax}
8631006
linear-gradient(red 0%, white 20%, blue 100%)
8641007

8651008
2. linear-gradient(red 40%, white, black, blue)
866-
=13=>
1009+
=1,3=>
8671010
linear-gradient(red 40%, white 60%, black 80%, blue 100%)
8681011

8691012
3. linear-gradient(red -50%, white, blue)
870-
=13=>
1013+
=1,3=>
8711014
linear-gradient(red -50%, white 25%, blue 100%)
8721015

8731016
4. linear-gradient(red -50px, white, blue)
874-
=13=>
1017+
=1,3=>
8751018
linear-gradient(red -50px, white calc(-25px + 50%), blue 100%)
8761019

8771020
5. linear-gradient(red 20px, white 0px, blue 40px)
8781021
=2=>
8791022
linear-gradient(red 20px, white 20px, blue 40px)
8801023

8811024
6. linear-gradient(red, white -50%, black 150%, blue)
882-
=12=>
1025+
=1,2=>
8831026
linear-gradient(red 0%, white 0%, black 150%, blue 150%)
8841027

8851028
7. linear-gradient(red 80px, white 0px, black, blue 100px)
886-
=23=>
1029+
=2,3=>
8871030
linear-gradient(red 80px, white 80px, black 90px, blue 100px)
8881031
</pre>
8891032
</div>
8901033

891-
<div class=example>
892-
The following example illustrates the difference between
893-
a gradient transitioning in pre-multiplied sRGBA
894-
and one transitioning (incorrectly) in non-premultiplied.
895-
In both of these example,
896-
the gradient is drawn over a white background.
897-
Both gradients could be written with the following value:
898-
899-
<pre>linear-gradient(90deg, red, transparent, blue)</pre>
900-
901-
In premultiplied space,
902-
transitions to or from "transparent" always look nice:
903-
904-
<object data="images/gradient2.svg" width="200"height="100">(Image requires SVG)</object>
905-
906-
On the other hand,
907-
if a gradient were to incorrectly transition in non-premultiplied space,
908-
the colors near "transparent" would noticeably darken to a grayish color,
909-
because "transparent" is actually a shorthand for ''rgba(0,0,0,0)'', or transparent black:
910-
911-
<object data="images/gradient3.svg" width="200"height="100">(Image requires SVG)</object>
912-
</div>
913-
914-
Note: It is recommended that authors not mix different types of units,
915-
such as px, em, or %,
916-
in a single rule,
917-
as this can cause a <a>color stop</a> to unintentionally try to move before an earlier one.
918-
For example, the rule ''background-image: linear-gradient(yellow 100px, blue 50%)''
919-
wouldn't require any fix-up as long as the background area is at least 200px tall.
920-
If it was 150px tall, however,
921-
the blue <a>color stop's</a> position would be equivalent to "75px",
922-
which precedes the yellow <a>color stop</a>,
923-
and would be corrected to a position of 100px.
924-
Additionally, since the relative ordering of such color stops
925-
cannot be determined without performing layout,
926-
they will not interpolate smoothly in
927-
<a href="http://www.w3.org/TR/css-animations/">animations</a>
928-
or <a href="http://www.w3.org/TR/css-transitions/">transitions</a>.
929-
930-
Note: The definition and implications of "premultiplied" color spaces are given elsewhere in the technical literature,
931-
but a quick primer is given here to illuminate the process.
932-
Given a color expressed as an rgba() 4-tuple,
933-
one can convert this to a premultiplied representation
934-
by multiplying the red, green, and blue components by the alpha component.
935-
For example, a partially-transparent blue may be given as rgba(0,0,255,.5),
936-
which would then be expressed as [0, 0, 127.5, .5] in its premultiplied representation.
937-
Interpolating colors using the premultiplied representations
938-
rather than the plain rgba representations
939-
tends to produce more attractive transitions,
940-
particularly when transitioning from a fully opaque color to fully transparent.
941-
Note that transitions where either the transparency or the color are held constant
942-
(for example, transitioning between rgba(255,0,0,100%) and rgba(0,0,255,100%),
943-
or rgba(255,0,0,100%) and rgba(255,0,0,0%))
944-
have identical results whether the color interpolation is done in premultiplied or non-premultiplied color-space.
945-
Differences only arise when both the color and transparency differ between the two endpoints.
9461034

9471035

9481036
<!--

0 commit comments

Comments
 (0)