7

The picture should explain it all. To the left is Safari 6 and behind it on the right is Chrome. Not only is the bottom half of the transparent red gradient completely wrong (which could perhaps be a case of overzealous premultiplied alpha) the top half is also darker which looks like a gamma-correctness problem.

This problem surfaces on Safari 6 on Mountain Lion and iOS6 Mobile Safari, however not on Safari 6 on Lion.

http://jsfiddle.net/ZUTYm/4

Has anybody found a solution for obtaining expected results? I need my gradients to involve alpha because I'm trying to fade text in and out of things.

Since I can't finish my edit till I put in real code here is the gradient definition: background-image: -webkit-linear-gradient(top, red, rgba(255,128,128,0), white);

enter image description here

Steven Lu
  • 41,389
  • 58
  • 210
  • 364
  • I opened the jsfiddle in safari 6.0.2 on a mbp running mountain lion getting the same result as chrome in your picture – Daniel Kurz Dec 04 '12 at 21:20
  • Thanks for your comment @DanielKurz I will check the exact versions of the software on the machine tomorrow. However the issue exists on iOS 6.0 as well which is troubling. – Steven Lu Dec 04 '12 at 21:28
  • you really think it's a bug of safari? because the bottom half should be a gradient from the background color to white, right? thats what safari shows – Daniel Kurz Dec 07 '12 at 12:36
  • I think part of the bug is in treating `rgba(x,x,x,0)` the same as `rgba(0,0,0,0)`. They are not the same...! Even setting the middle color stop to `rgba(255,128,128,0.1)` produces wrong results. The color is getting scaled by the alpha, this is *wrong*. – Steven Lu Dec 07 '12 at 16:11
  • the strange thing is, I look at your question and the jsfiddle from time to time and sometimes safari displays it the way chrome does and sometimes the way to recognized. – Daniel Kurz Dec 08 '12 at 21:16
  • It could be a display driver bug too... I've seen it on a Intel HD3000 (2011 MBA) and a HD4000 (new Mac Mini) – Steven Lu Dec 09 '12 at 00:19
  • I think you have the cause identified, the RGB values are being scaled by the Alpha. This explains the darkness at the top too, as the gradient runs to black instead of reddish gray. And I wouldn't say this is *wrong*, just different, unless there's a spec which is explicit on how it should work. Too bad there's no way to combine two different gradients into a single image. – Mark Ransom Dec 12 '12 at 23:55
  • Behavior still inconsistent with Chrome as of Safari Version 6.0.4 (8536.29.13). – Steven Lu May 11 '13 at 05:14

1 Answers1

4

I was able to reproduce the problem on Mac 10.8.1 Safari 6.0 (8536.25) and iOS Safari 6.0.1. I think applying a -webkit-mask-image instead of a transparent color-stop avoids the issue:

.grad-bg {
    background-image: 
        -webkit-linear-gradient(top, #ff0000, #fff);
    height: 100%;
}

.masked {
    -webkit-mask-image:
        -webkit-linear-gradient(top, white, transparent, white);
}

jsFiddle

In the image, the top shows over a white background, bottom shape shows over an opaque gradient background of the same colors.

Top shows over a white background, bottom shape shows over an opaque gradient background of the same colors.

(Many edits.)

tiffon
  • 5,040
  • 25
  • 34
  • I think for consistency you need to make the middle value `rgba(0,0,0,0)`. – Mark Ransom Dec 13 '12 at 02:17
  • I don't follow; OP has `rgba(255,128,128,0)` and the same value is in the linked [jsFiddle](http://jsfiddle.net/ZUTYm/4). If the middle values was all 0s, there would be more grey in the gradient. – tiffon Dec 13 '12 at 02:23
  • But that's the problem, Safari is interpreting `rgba(255,128,128,0)` as `rgba(0,0,0,0)` and to make Chrome consistent you need to make them both use the same values. – Mark Ransom Dec 13 '12 at 02:43
  • I added a screenshot. I still don't follow you. If Safari is interpreting `rgba(255,128,128,0)` incorrectly, then it seems like the idea would be to get Safari to interpret it correctly. I guess it could go either way, you're working around Safari's bug either by restricting the gradients you use (fit Chrome to Safari) or by adding redundant information to the CSS file (work around Safari's bug). It's worth noting, though, that Safari 6.0.2 renders it the way Chrome does. – tiffon Dec 13 '12 at 03:01
  • Interesting. Which version did you use to generate the screenshot? I honestly don't think it's incorrect for a fully transparent color to be treated as if it had no RGB values at all, it's just a different way of interpreting it - even if it is contrary to some expectations. Obviously it would be better if every browser made the same interpretation but it doesn't rise to the level of a bug unless it violates some specification somewhere. – Mark Ransom Dec 13 '12 at 03:12
  • Interesting workaround, thanks @tiffon. I think this will still cause a discrepancy as what I am trying to do is overlay this transparency-gradient over an opaque-gradient, and the idea of course is for the **colors** to match up exactly. In placing additional color stops to force the effect we can dramatically reduce the area of discrepancy but the result is still gonna be wrong, as any time that `alpha < 0` the color is scaled wrong... But it's definitely a step forward because this is a way to actually get the red color to show up at least. – Steven Lu Dec 13 '12 at 16:43
  • @StevenLu Thanks. From your comment, it sounds like the bug is being minimized. But, I think the extra color-stops actually **avert** the bug. I've updated the [jsFiddle](http://jsfiddle.net/ZUTYm/13/) to use an opaque gradient background. – tiffon Dec 13 '12 at 17:26
  • @MarkRansom I used this [jsBin](http://jsbin.com/opogon/1/) to generate the previous image. I agree; RGB values in a transparent color are arbitrary--for a pixel. But, when colors need to be interpolated, the RGB values are critical. I think the rendering discrepancy is a bug related to a faulty CSS optimization. During interpolation, the RGB values for the opposing color (red at top-half, white for the bottom) are the only RGB values used. I can only see this as a bug. I think the extra color-stops work because they avert the faulty optimization. – tiffon Dec 13 '12 at 17:50
  • I don't think it's a CSS optimization at all, I think it's the result of using [premultiplied Alpha](http://en.wikipedia.org/wiki/Premultiplied_alpha) for the stop colors. When you multiply an alpha of 0 into the RGB components, they all become 0 no matter what they started out as. The extra stops work by introducing a half-way point that still has some color left after the multiplication. – Mark Ransom Dec 13 '12 at 18:23
  • @MarkRansom Damn, [you're right](http://jsbin.com/opogon/2/); I've deluded myself... I retract my **avert** remarks, lol. – tiffon Dec 13 '12 at 19:22
  • I have updated the fiddle [here](http://jsfiddle.net/ZUTYm/15/) so it is covering the same opaque gradient in the square underneath it. It looks significantly better, in that the color is not zeroed out, but still not matching up perfectly as it is darker due to premultiplied alpha. – Steven Lu Dec 13 '12 at 20:53
  • I think [this fiddle](http://jsfiddle.net/ZUTYm/24/) gets the job done. The covering gradient is just a regular gradient but a [`-webkit-mask-image`](https://developer.mozilla.org/en-US/docs/CSS/-webkit-mask-image) is applied to it. – tiffon Dec 13 '12 at 23:18
  • Nice. Looks like using a mask image to set alpha will unambiguously specify the appearance. – Steven Lu Dec 14 '12 at 03:58