Bulletproof, cross-browser RGBA backgrounds, today

UPDATE: New version

First of all, happy Valentine’s day for yersterday. :) This is the second part of my “Using CSS3 today” series. This article discusses current RGBA browser support and ways to use RGBA backgrounds in non-supporting browsers. Bonus gift: A PHP script of mine that creates fallback 1-pixel images on the fly that allow you to easily utilize RGBA backgrounds in any browser that can support png transparency. In addition, the images created are forced to be cached by the client and they are saved on the server’s hard drive for higher performance.

Browsers that currently support RGBA

These are:

  • Firefox 3+
  • Safari 2+
  • Opera 10 (still in beta)
  • Google Chrome

In these browsers you can write CSS declarations like:

background: rgba(255,200,35,0.5) url(somebackground.png) repeat-x 0 50%;
border: 1px solid rgba(0,0,0,0.3);
color: rgba(255,255,255,0.8);

And they will work flawlessly.

Internet Explorer

Surprisingly, it seems that Internet Explorer supported RGBA backgrounds long before the others. Of course, with it’s very own properietary syntax, as usual:

filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#550000FF, endColorstr=#550000FF);

And since nothing is ever simple with IE, IE8 requires a special syntax which has to be put before the first one to work properly in IE8 beta1:

-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#550000FF, endColorstr=#550000FF)";

The code above actually draws a gradient from rgba(0,0,255,0.33) to rgba(0,0,255,0.33) using a Microsoft-proprietary “extended” hex format that places the Alpha parameter first (instead of last) and in the range of 00-FF (instead of 0-1). The rest is a usual hex color, in that case #0000FF.

Caution: The “gradients” that are created via the gradient filter are placed on top of any backgrounds currently in effect. So, if you want to have a background image as well, the result may not be what you expected. If you provide a solid color as a background, it will also not work as expected (no alpha transparency), since the gradients created are not exactly backgrounds, they are just layers on top of backgrounds.

Problems with the filter method

  • Filters are bad for client-side performance.
  • Filters cause the text rendering to be aliased and especially when it’s bold and there is no background-color set it becomes completely unreadable. (the worst disadvantage if you ask me)
  • Filters only work with IE. What about Firefox 2- and Opera 9.6-?
  • Filters are lengthy (especially now that you have to include 2 different syntaxes) so they significantly increase the size of your CSS when used frequently.
  • You have to convert the red, green and blue values to hex to use that method.
  • To use a filter, the element has to have Layout. This is usually done via zoom:1. More non-standard clutter in your CSS.
  • Doesn’t play along well with other workarounds, since it doesn’t modify the background of the element.

So, personally, I only use that approach sparingly, in particular, only when “no/minimum external files” is a big requirement.

A bulletproof solution

My favored approach is to use rgba() for all RGBA-capable browsers and fallback pngs for the ones that don’t support RGBA. However, creating the pngs in Photoshop, or a similar program and then uploading them is too much of a fuss for me to bare (I get bored easily :P ). So, I created a small PHP script that:

  • Creates a 1-pixel png image with the parameters passed for red, green, blue and alpha. No need to convert to hex.
  • Supports named colors, to speed up typing even more for colors that you use commonly in a site (it includes white and black by default, but you may easily add as many as you like).
  • Stores the generated images on the server, so that they don’t have to be created every time (generating images on the fly has quite an important performance impact).
  • Forces the images to be cached on the browser so that they don’t have to be generated every time (even though their size is very small, about 73 bytes).

Here it is: rgba.php

You use it like this:

background: url(rgba.php?r=255&g=100&b=0&a=50) repeat;
background: rgba(255,100,0,0.5);

or, for named colors:

background: url(rgba.php?name=white&a=50) repeat;
background: rgba(255,255,255,0.5);

Browsers that are RGBA-aware will follow the second background declaration and will not even try to fetch the png. Browsers that are RGBA-incapable will ignore the second declaration, since they don’t understand it, and stick with the first one. Don’t change the order of the declarations: The png one goes first, the rgba() one goes second. If you put the png one second, it will always be applied, even if the browser does support rgba.

Before you use it, open it with an editor to specify the directory you want it to use to store the created pngs (the default is 'colors/') and add any color names you want to be able to easily address (the defaults are white and black). If the directory you specify does not exist or isn’t writeable you’ll get an error.

Caution: You have to enter the alpha value in a scale of 0 to 100, and not from 0 to 1 as in the CSS. This is because you have to urlencode dots to transfer them via a URI and it would complicate things for anyone who used this.

Edit: It seems that IE8 sometimes doesn’t cache the image produced. I should investigate this further.

IMPORTANT: If your PHP version is below 5.1.2 perform this change in the PHP file or it won’t work.

Why not data:// URIs?

Of course, you could combine the IE gradient filter, rgba() and data:// URIs for a cross-browser solution that does not depend on external files. However, this approach has some disadvantages:

  • All the disadvantages of filters mentioned above.
  • You can’t be spontaneous in your CSS and changes are difficult. Every time you want to use RGBA, you have to resort to some converter to create the png and it’s data:// URI. Unless you are some kind of a cyborg with an embedded base64 encoder/decoder in your head :P
  • Larger filesize (you have to use 4-5 declarations (the rgba() one, the data:// one, 2 filters, one for IE7- and one for IE8 and a zoom:1; to give the element “layout” so that filters can be applied) instead of 2, and the data:// URI has the same size as the png). Also, the data:// URI can not be cached so every time you use it, you increase the filesize even more.  Ok, you save an http request per use, but is it worth it?

and some advantages:

  • You will not see the site without a background for even a single millisecond. Since the png is embedded in the CSS, it’s loaded as soon as the CSS itself is loaded. If your site background is too dark and you rely on the RGBA background to make the content legible, you might want to consider this solution.
  • No external files, no extra http requests.
  • The filter method works in IE6- without the script for transparent PNGs.

Choose the method that fits your needs better. :)

RGBA is not only for backgrounds!

It’s also for every CSS property that accepts color values. However, backgrounds in most cases are the easiest to workaround. As for borders, if you want solid ones, you can simulate them sometimes by wrapping a padded container with an RGBA background around your actual one and giving it as much padding as your desired border-width. For text color, sometimes you can fake that with opacity. However, these “solutions” are definitely incomplete, so you’d probably have to wait for full RGBA support and provide solid color fallbacks for those (unless someone comes up with an ingenious solution in <canvas>, it’s common these days :P ).

  • Pingback: Check whether the browser supports RGBA (and other CSS3 values) « Lea Verou

  • Bridget

    This is a great idea. I’ve been playing around with it, but it doesn’t appear to work with Opera 9.64 (the only non-RGBa browser I’ve tested in). Maybe I’m doing something wrong?

    I definitely have the declarations in the right order in my css file. Should the rgba.php file be in any specific directory? It doesn’t appear to be the case when I looked at the php file for further instruction — and I’ve even tried moving it around to no avail.

    The png never seems to get generated.

    Any thoughts what my problem is?

  • http://leaverou.me Lea Verou

    Hi Bridget!
    Try to directly navigate to rgba.php with some parameters (if you call rgba.php on its own, or if you miss some parameters it won’t work. It needs either r,g,b and a, or name and a specified, otherwise it won’t know which color you want. For example, rgba.php?r=255&g=30&b=100&a=50 or rgba.php?name=white&a=30) and see if it works. If it does, you should see a 1-pixel image (try to zoom in if you can’t easily spot it). Any kind of error message indicates a problem.
    As for the directory it should be in, there is no requirement, as long as you reference it in your CSS correctly (remember: images in CSS are referenced in relation to the CSS file).
    If it works fine on its own, then you are doing something wrong in the CSS, and it would help if you posted that part of your CSS code. :)
    In any case, don’t worry, I’ll do my best to help. :)

  • Bridget

    I got an error message when navigating directly to the file with parameters like you suggested. I’ve replaced the name of the site where I’m testing with example.com, just so I don’t get hits for silly stuff like this and skew my stats. :)

    The image “http://example.com/ww_site/rgba.php?r=255&g=30&b=100&a=50” cannot be displayed, because it contains errors.

    So, does this help us figure out what my problem is?

  • http://leaverou.me Lea Verou

    If you navigate to http://leaverou.me/wp-content/themes/leaverou/rgba.php?r=255&g=30&b=100&a=50 you’ll see it works here, so I guess it’s a problem with your server’s setup.
    First thing on the checklist: Which PHP version are you using?
    If you are unsure, you can see that by creating an empty php file with

     < ?php phpinfo(); ?> 

    as the only contents and navigating to it.

    PS: WordPress somehow messes up the code above. There should be no empty space between < and ?php

  • Bridget

    Thanks for troubleshooting. I didn’t mean to eat up part of your weekend. :)

    PHP Version 4.4.9 is the answer for what version of PHP is on my server.

  • http://leaverou.me Lea Verou

    I suspect that there lies the root of the problem: In our server (where this blog is hosted as well) we use PHP 5.2.6 with GD 2.0.34.
    I’m now going to check whether there’s an issue with PHP 4.4.9 for any of the functions I’ve used in the PHP manual. In the meantime, you could check and tell me what your GD version is to make this easier (in phpinfo it should be under “GD version” in the gd table).
    I’ll post a new comment when I find something relevant.

    Don’t worry about eating up my weekend, I’m always happy when my scripts help someone and I consider it my obligation to help when there’s an issue with them.

  • Bridget

    Lea,

    The answer to the GD version is: bundled (2.0.28 compatible)

    However, I do have MAMP installed for local testing which is PHP5.2.5; GD: bundled (2.0.34 compatible)

    So, I’ll also try getting it to work there so that I know how to use it properly, but would still love help making sure it can work on the “live” server, if that is possible. Certainly, I am not asking you to write anything special to make it work for less than PHP5. I can always ask my host if they have a PHP5 server to move me to, if I figure out how to use it right on MAMP. :)

    I have gotten it to generate the png on my local server. I think I’ve not pointed to the right place in the css for that attempt.

  • http://leaverou.me Lea Verou

    The only difference I found in the functions I used between PHP 4.4.9 and PHP 5.2.6 was that the imagepng() function accepts only 2 arguments in PHP 4.4.9 and 4 in PHP 5.2.6. However, I didn’t actually use the last 2, I just specified 0 and NULL for them, so it should work. I never recall PHP throwing an error if you use more arguments than needed. However you may try deleting the last 2 arguments in line 101 (convert imagepng($img,$filepath,0,NULL); to imagepng($img,$filepath);) although I doubt it will fix the issue. You never know though…

    I will try to investigate it further. If it only works with PHP5+ I should at least state it in the post so that people know it in advance. I guess that if I find out why it doesn’t work on PHP4 it won’t be too hard to fix it though.

  • Bridget

    Thanks so much, Lea. I did get it working on MAMP – so PHP5 is good, as you already know. I’ll try what you said for the PHP4 issue and report back.

    I really am excited at the idea of making RGBa work across browsers with something as easy as this. If PHP4 ends up being out of the question, I’ll ask to change servers. I want a playground where I can test out fun stuff — not be stuck in the dark ages! :)

  • Bridget

    Woo hoo! Lea, you rock. removing those two parameters made it work for PHP4. Hopefully, if people read through this thread, they can fix it themselves — or you could update the article to explain the easy work around.

    Again, YOU ROCK!

  • http://leaverou.me Lea Verou

    Woohoo! I’m really glad we solved it! :D

    Article updated ;)

  • http://alexlingris.com lexx

    This is simply great. I am going to use it right now for a site I just finished (full of rgba :P)

  • http://leaverou.me Lea Verou

    Cool! Let me know how it went! :)

  • http://jlix.net/ Sander Aarts

    Wouldn’t it be better to make the image a bit bigger?
    It won’t differ that much in file size, but the browser does not need to calculate as much. Not sure about modern browsers, but some years ago you could notice the difference between painting a background from a 1 pixel image and one from a 10×10 pixel image.

    BTW, great blog with very useful info. And besides that it’s always nice to see more women who write about this kind of stuff and at this level. It should not matter of course, but I think it’s still special.
    Anyway, glad I landed here ;-)

  • http://leaverou.me Lea Verou

    Hi Sander! Thanks for the kind words!! :D

    You can easily make the generated image 10×10 if you change the following line:

    $img = @imagecreatetruecolor(1,1)

    to

    $img = @imagecreatetruecolor(10,10)

    Haven’t tried it, but it should work.

    As for the gender part, you’d probably be surprised to learn that the first programmer ever was a woman, and the first compiler ever was also written by a woman. ;) :)

    • http://jlix.net/ Sander Aarts

      Those were truly amazing people!
      But though I know that women have been involved in computer science from the early days on, I still don’t know many women today that have the same JavaScript skills you have. Perhaps they’re just not so vocal about it. But even the recent ALA survey results (http://aneventapart.com/alasurvey2008/01.html#gdbjt) tell us that only 6.8% of today’s web developers are women.

      • http://leaverou.me Lea Verou

        Yeah, I’ve seen the ALA survey results too, and they are truly disappointing… :( They made me feel a bit lonely (although I knew the percentage was small, I didn’t expect it to be THAT small!).

        Here’s a blog post I read recently about the reasons that there aren’t many female geeks around: http://blog.sugarenia.com/archives/rantings/on-women-in-tech . I had read a better one somewhere in the past but I can’t seem to find it now. :/

  • http://somadesign.ca/ Matt Wiebe

    Lea, great work here. I already have a site in development that I want to use this on.

  • http://leaverou.me Lea Verou

    Let me know how it went Matt :)

    By the way, your site is amazing!! Great design!

  • http://desandro.com Dave DeSandro

    Lea, thanks for going into detail on the options for rgba.

    You can’t be spontaneous in your CSS and changes are difficult. Every time you want to use RGBA, you have to resort to some converter to create the png and it’s data:// URI. Unless you are some kind of a cyborg with an embedded base64 encoder/decoder in your head

    I’ve been playing around with the canvas element lately. Since the image it outputs is encoded in data URI, I’ve found a shortcut to for those converters – just create the canvas in HTML. I’ve developed a quickie canvas creator that uses jQuery so you can just plug in the code for the canvas element and not worry about all the other HTML and JS. Might be of use for some of the rgba work arounds.

  • http://twitter.com/jrosell jrosell

    Good idea!
    IMHOO you must check maximum colors generation for robots bursts by kidies

  • http://leaverou.me Lea Verou

    @jrosell: Good point. However I can’t think of a workaround, given the fact that this could also be used in a site where the user would be able to customize the theme and select their own rgba colors, so there could be lots of colors created legitimately… Perhaps an idea could be to allow the developer to set a limit?

    @Dave DeSandro: Interesting script there! However, I’m afraid you missed my point a bit. Even having to go to your site (or any site) to do the conversion is too much of a hassle just to change a color or it’s transparency a little bit. If you are suggesting that somebody could build a javascript solution for that, your point is valid of course, and such a script would be interesting. However, what happens to this little percentage of users that have disabled js? In most cases where rgba backgrounds are used, the text would be completely unreadable without them.

  • Pingback: Fixed the blog in IE! | Hereward Cooper

  • Mantish

    Hi, I love this solution, it’s awesome, thanks a lot.
    However, I haven’t been able to make it work in IE6. Do you know which script works with your PHP script?

    • http://leaverou.me Lea Verou

      PNG alpha transparency in IE6 is probably its most popular bug. Just use any script that fixes it and it should be ok (just ensure it works with background-repeat).

      I’d suggest DD_belatedPNG by Drew Diller, but it’s been a while since I gave up on IE6, maybe there’s something even better out there by now.

      • Mantish

        Actually I’ve been using DD_belatedPNG, and it works ok with regular png images, but not with the ones generated by your script. Maybe there’s something I’m missing?

        • http://leaverou.me Lea Verou

          That’s very strange. Try creating a simple test case with a locally stored copy of such a png and sending it to Drew along with a brief description of the bug. You’ll greatly help him and all web developers that use his script. :)

        • http://codigoweb.co/ Mantish

          Well, after reading about DD_belatedPNG, I found out that the images have to have a png extension in order for the script to work. So I had to modify DD_belatedPNG script to get it to work.
          I wrote a blog post about it: http://codigoweb.co/fondos-rgba-en-ie6/
          It’s in spanish…but anyway, maybe it’s useful for you or any other readers.

        • http://leaverou.me Lea Verou

          Oh, I see. Another workaround could also be to use an .htaccess to make the images have a .png extension. It would also solve the caching issues it has in IE sometimes.

  • Pingback: Fondos RGBA en IE6 | Código Web

  • Pingback: How to achieve cross-browser RGBA support with Compass :: Aaron Russell

  • Pingback: Freelance Front End Web Developer, Surrey, Hampshire & London – HTML5, CSS3, JS, jQuery, PHP

  • Darek

    Thanks for the fix – but Im having a strange problem….

    Everything was working for a minute, then I refreshed, and now I get this error:
    “Call to undefined function apache_request_headers() on line 69″

    What happened? It worked for one page load, then it broke. Im baffled.

    • http://leaverou.me Lea Verou

      Darek, try using the new version, there’s a link in the beginning of this post. :)

  • http://binarym.com/ matt mcinvale

    very nice solution! thank you.

  • Kalarm

    Not quite bulletproof since it doesn’t work in IE…

    Want it or not, there are still people who use it, and it is our job to make things work for them too, or at least make it so the website doesn’t become a torture for their eyes.

    • http://leaverou.me Lea Verou

      In which way it doesn’t work in IE?

  • http://www.KeganBall.com Kegan

    I got this to work and I the transparency shows up at first. However when I did a refresh in IE8, the png image seems to disappear. When I go into the ‘colors’ directory on my server and delete the file then do a refresh in IE, it works again. However as soon as I do the refresh it disappears. I can repeat this over and over.

    The transparency works fine in Firefox.

    I’m using this on a WordPress 3.0.1 install with very few plugins and no caching plugins.

    • http://leaverou.me Lea Verou

      My guess is that for some reason, the file that’s saved on your server has some issue. Have you tried navigating via HTTP to that file? Does it display?

      As for when it works: It works in Firefox because Firefox supports RGBA natively, so it doesn’t even use the image.
      It also works the first time when no image is saved yet because it’s served directly from the php file, not the saved one.

      • http://www.KeganBall.com Kegan

        Thank you for your response.

        Yes the file does display when I navigate to it directly. http://209.42.194.146/rgba/colors/color_r0_g0_b0_a114.png

        I’m using the script to make the menu semi-transparent. Your script works the first time. But as you said, the first time it’s pulling it directly from the script.

        I can navigate directly to it… So why won’t it display when after the first time?

        • http://www.KeganBall.com Kegan

          I just replaced:
          background: url(http://209.42.194.146/rgba/rgba.php?name=black&a=10) repeat;
          with:
          background: url(http://209.42.194.146/rgba/colors/color_r0_g0_b0_a114.png) repeat;

          And now I can see the .05 transparency.

          So I can get it to work temporarily, but why won’t it work with the script in place?

        • http://leaverou.me Lea Verou

          Apparently, there’s an issue when the script tries to fetch the image. I can help you into debugging it, but I just noticed you commented on the original post and not the version 2 post. Are you using the old version? If so, upgrading will probably fix it.

  • http://leaverou.me Lea Verou

    Closing comments, since this version is outdated by now. Please anyone, use the new version and post any questions/issues in this post: http://leaverou.me/2009/10/new-version-of-rgba-php-is-out/

  • Pingback: rgba.php v1.2: Improved URL syntax, now at Github « Lea Verou

  • Pingback: New version of rgba.php is out! « Lea Verou

  • Pingback: SWL-Projekt » rgba.php v1.2: Improved URL syntax, now at Github

  • Pingback: Utilizando CSS3 hoy (2): Colores y opacidad utilizando RBGAemenia.es | emenia.es

  • Pingback: rgba.php v1.2: Improved URL syntax, now at Github | Lea Verou

  • Pingback: A Look Into: CSS3 Linear Gradient

  • Pingback: A Look Into: CSS3 Linear Gradient / Photoshop CS6 Download

  • Pingback: A Look Into: CSS3 Linear Gradient

  • Pingback: A Look Into: CSS3 Linear Gradient | Android News

  • Pingback: A Look Into: CSS3 Linear Gradient | DigitalMofo

  • Pingback: A Look Into: CSS3 Linear Gradient | Best Web Consulting company in Nashik, India with Creative and Professional Website Design, Content Management Systems, Wordpress Experts, Ecommerce SEO, and more..

  • Pingback: How To Work With Transparent Colors And Images In CSS - Vanseo Design

  • Pingback: Fallbacks - Noback

  • Pingback: rgba for IE