-
Notifications
You must be signed in to change notification settings - Fork 679
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-images-4] Clarifying CSS gradient rendering for edge cases involving "longer hue" interpolation #11381
Comments
To follow up, here is what I think my codepen example ought to look like, by my reading of the spec: Currently, none of the three tested browsers produces this rendering. So if my understanding is correct, and assuming we don't want to modify the spec in the light of what browsers are actually doing, then all three engines have bugs here. |
It occurs to me that it should be possible to emulate a I made a copy of my codepen example using this, and this does indeed render all the examples as I expected(*). I'm feeling increasingly sure that the current behavior we see of "projecting" the So unless I'm missing some extra part of the spec that supports these behaviors, I'm intending to file bugs against the browsers and create some WPT tests to check the behavior. (*) Except that Safari renders swatch (l) in solid red instead of blue, as mentioned at the end of the original description. That is surely a webkit bug. |
I would be very very worried about changing the appearance of sites that have come to depend on the current behavior, though maybe not many do. Is it possible to craft a query against HTTPArchive that looks for the gradient syntax that you are testing (i.e. gradient styles that hit the conditions of interest). I would try to change the spec rather than browsers if this turns out to be something that has significant usage. Even though this does look to me like some kind of browser problem with the treatment of identical or near-identical stop colors. |
It's not "identical or near-identical stop colors" that are at issue here; it's what browsers do with |
I am seeing differences between Firefox, Chrome and Safari regarding how gradients with the "longer hue" interpolation method are rendered. I think I understand what the spec expects, but none of the browsers tested get this right, so I'd like to confirm my interpretation — and perhaps some clarification or additional examples may be needed in the spec.
Testcase: https://codepen.io/jfkthame/pen/azopZOx
(Note that there have been some recent patches to gradient rendering in Firefox. The description below refers to current Nightly builds; older versions have some different and less self-consistent results.)
This renders a number of 100px-wide gradient swatches, all of them defined as linear-gradient(to right in hsl longer hue, ...) with two color stops, red and blue, at a variety of positions. (The red and blue tick-marks above and below each swatch indicate the positions of the color stops defining the gradient.)
Results I'm seeing in Firefox Nightly, Chrome Canary, and Safari Tech Preview:
The simplest case is (a), with the red stop at the left edge and the blue stop at the right. No issues here: we simply render a gradient from red to blue, going "the long way around" the HSL wheel.
What happens if the first and last stops defining the gradient do not cover the full extent of the area to be rendered? In (b), the blue stop is in the middle, so what happens in the right-hand half of the swatch? According to https://drafts.csswg.org/css-images-4/#coloring-gradient-line,
which seems to imply that the right-hand half of (b) should be solid blue. However, all three tested browsers actually paint a further gradient here, with a full cycle of the HSL wheel from the blue stop at 50px all the way around to blue again at the 100px edge. I presume the browsers are adding an "implicit" blue color stop at the right-hand edge, and then performing a longer-hue interpolation between the actual blue stop at 50px and that implicit one. I don't see any justification in the spec for this behavior: I think it's a bug, but given that all three browsers behave this way, maybe I'm missing something?
Example (c) is similar: here, both the red and blue color stops are moved in from the edges of the swatch, so I think the expected rendering should have 20px of solid red at the left, and 25px of blue at the right, with the longer-hue gradient from red to blue in between. But all three browsers also render a complete 360° gradient in both the left and right portions, outside the defined color stops. Bug?
(Aside: the description of linear-gradient on MDN https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/linear-gradient
may be a bit misleading here. That first sentence might be understood to imply creating an extra stop at 0%, duplicating the first declared color, rather than simply painting that color from its stop position back to 0%; and analogously, although the wording is less ambiguous, an implementer might think they should duplicate the last declared color at 100%. And that would indeed result in the observed behavior. But if my understanding of the actually-expected behavior is correct, I'll suggest rewording this for better clarity.)
Interestingly, in example (d), where the blue stop is moved beyond the right-hand end of the swatch, Chrome and Safari suddenly switch their behavior and now do not use a gradient in the area to the left of the red stop: they turn this into solid color. (Firefox, on the other hand, continues to apply a gradient there, just like in the preceding examples.) I think the Chrome/Safari behavior here is what the spec requires, but I don't understand why they only do this correctly once the blue color stop is beyond the end of the rendered area.
Example (e) shows the equivalent case with the red stop placed beyond the left edge: now, Chrome and Safari render a solid color for the area beyond the blue stop, while Firefox still paints a gradient there.
Examples (f) and (g) serve to illustrate the abrupt change in behavior in Chrome and Safari. The two stops are just shifted right by 1px in (g) compared to (f). In Firefox, this just results in a barely-perceptible shift in the gradient; but in Chrome and Safari it drastically changes the result.
QUESTION 1: Am I right in thinking that any area before the first color stop or after the last color stop should simply render as a solid color, or is longer-hue interpolation expected to somehow "project" into these areas (as the browsers currently do, though not entirely consistently)?
The second group of swatches, (h) through (l), have the two color stops at the exact same position. My reading of the spec is that the correct rendering would have solid red to the left of the stop position, and solid blue to the right. But all three browsers actually render a complete 360° gradient: to the right of the color stops, they render blue-to-blue (all the way around the hue circle), and to the left they render red-to-red (all the way around). For (h) through (j), this result is consistent across all the browsers, and appears to result from adding "implicit stops" at the left and right edges of the swatch, duplicating the color of the nearest real stop.
In example (k), the position of the red and blue stops has been moved beyond the right-hand edge of the swatch. In Firefox, this "stretches" the gradient to the right; it still begins with red at the left edge, but the visible gradient no longer cycles all the way back to red because the stop is outside the swatch area. In Chrome and Safari, on the other hand, the end of the 360° gradient seems to be "clamped" to the right-hand side of the swatch, so (k) looks identical to (j). I can't see any justification for that behavior — though I think the browsers are wrong to be rendering a gradient at all in this case.
Finally, in (l) the stops have been moved before the left-hand edge of the swatch. Again, Firefox stretches the gradient; Chrome "clamps" the left edge, so that (l) is identical to (h). Safari renders this example the same as (j) and (k), which I think is a bug.
QUESTION 2: Is a longer-hue linear gradient with stops at a single position a special case that should render some kind of gradient (as all browsers currently do, regardless of where the stops are positioned), or is that just an implementation bug?
(Note that there are a couple of existing WPT tests that expect this behavior; e.g. see http://wpt.live/css/css-images/gradient/gradient-single-stop-longer-hue-hsl.html. I'm suggesting this may be wrong. Does the web depend on it?)
The text was updated successfully, but these errors were encountered: