Support two-position gradient color stops - #199
Merged
TylerBrinks merged 1 commit intoJul 23, 2026
Merged
Conversation
CSS Images 4 defines a color stop's length as
<color-stop-length> = <length-percentage>{1,2}, so a stop may carry two
positions - "red 0 50%", equivalent to two same-color stops, one at each
position. ToGradientStop consumed only a single trailing position, so
any stop with two was rejected and the whole gradient failed:
linear-gradient(red 0 50%, blue 50% 100%) /* dropped */
radial-gradient(red 0 8px, blue) /* dropped */
Parse a second position when one is present and keep both, in source
order, so the stop round-trips as authored rather than losing a
position. The two-position form requires a color (a bare
<length-percentage> is a single-position <linear-color-hint>), and three
positions remain invalid.
The radial case needed no separate change: ConvertFirstArgument already
returns null for a leading color, so "red 0 8px" was always treated as
the first stop - it just could not be parsed until now.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A gradient color stop with two positions is rejected, taking the whole gradient with it:
CSS Images 4 §3.5.1 defines a stop's length as:
with the note that two positions is "equivalent to specifying two color stops with the same color, one for each position" — a convenient way to make solid bands.
GradientConverter.ToGradientStopconsumes only a single trailing<length-percentage>, so a stop written with two leaves a leftover token,ToGradientStopreturns null, andToGradientStopsfails the entire value.Fix
Parse a second position when one is present, and keep both in source order so the stop round-trips as authored —
red 0 50%serializes back asred 0 50%, notred 50%.StopValuenow holds an optional second position and joins whatever is present.Guards from the grammar:
<length-percentage>is a single-position<linear-color-hint>, so0 50%with no color stays invalidred 0 25% 50%) stay invalidThe radial case needed no separate change.
ConvertFirstArgumentalready returns null for a comma group that begins with a<color>, sored 0 8pxwas always routed to the first stop — it simply couldn't be parsed until now. Confirmed byradial-gradient(red 0 8px, blue)passing with only this change.Tests
9 cases in
Gradient.cs: three two-position gradients (linear, linear-with-angle, radial) asserting the exact serialized value; three single-position/no-position/hint cases that must stay legal; and two malformed cases (three positions, two bare positions) that must stay rejected.3 fail on
master. The full suite (1263 existing tests) stays green with no existing assertion modified, and all seven target frameworks build with no new warnings.