03 May 2012

Browser inconsistencies with ‘transparent’ in CSS gradients

A while back, as I was working on my custom user style for , I noticed a peculiar behavior when I tried to apply a CSS gradient to the feed title section, specifically something like “starting from solid white to 20% transparent, to 80% transparent and finally back to a solid shade of blue”. The result was not was I expected: the transition from solid colors to transparent was murky, mixed with grey. I started experimenting with different combinations of colors and gradients and in different browsers. Finally I discovered that there is a difference in the way browsers interpret ‘transparent’ in gradients: and actually treat transparent as ‘black transparent’, causing gradients to add dark shades where none should appear according to the CSS code; on the other hand makes a smooth transition from the starting solid color to transparency (Internet Explorer doesn’t support gradients at all in the stable channel yet).

During this troubleshooting I built a small example on jsFiddle to illustrate the difference: on a red background two boxes filled with vertical gradients: on the left a solid gradient going from white to red and then back to white; on the right white – transparent – white. In my opinion the rendering should be identical, as the right gradient should simply reveal the red background underneath. Instead, Chrome and Firefox add grey strips to the transition from solid to transparent, as you can see in the screenshots and if you visit the test fiddle in those browsers. You get similar results with both the transparent keyword and the RGBA() function with alpha set to zero or some small value.

  • Test linear gradient solid to transparent Chrome
    Resulting rendering in Chrome (identical with Firefox)
  • Test linear gradient solid to transparent Opera
    Opera rendering – what I actually expected

Of course, the CSS3 specification for linear gradients is still in draft, the browser support is still experimental (i.e. with browser-specific prefixes) so there are bound to be rendering differences. Going through specs, I noticed an example closely resembling mine, as well as an explanation for the strange results you get in Chrome and Firefox (it seems to me that Opera has implemented the specs correctly in this case):

The following example illustrates the difference between a gradient transitioning in pre-multiplied sRGBA and one transitioning (incorrectly) in non-premultiplied. In both of these example, the gradient is drawn over a white background. Both gradients could be written with the following value:

linear-gradient(90deg, red, transparent, blue)

In premultiplied space, transitions to or from "transparent" always look nice:

On the other hand, if a gradient were to incorrectly transition in non-premultiplied space, the colors near "transparent" would noticeably darken to a grayish color, because "transparent" is actually a shorthand for ‘rgba(0,0,0,0)’, or transparent black.

Which ties again into the debate over Opera starting to support some –webkit-prefixes: even if Opera’s rendering engine picks up the –webkit property, the designer should still test the result in Opera, because it could well be not what he expected (although in this particular case it actually looks better than what you would get in WebKit). The end user should get a better experience anyway, closer to the original design, instead of the fallback for older browsers.

There are other quirks in the linear gradients spec; you can read some very interesting examples in this article.

Update: Two and a half years later(!), Firefox is the last major browser with this bug and they are finally fixing it the upcoming version 36:

Later update: it seems I was wrong with my previous update – almost five (!) years later, Safari still uses the ugly (and wrong) rendering, transitioning through black. There are, as always, workarounds, but to me it reads like another (small) argument in favor of the idea that Safari is holding back the web.

Post a Comment