Tiffany B. Brown

a mish-mosh of stuff

Thoughts on practices for CSS Gradients

Examples of CSS gradients are cropping up in the wild, and with good reason. CSS gradients:

  • don’t require the additional HTTP request of an image file.
  • are easier to modify than image files.
  • “weigh less” than most image files.

That’s the ideal, at least. In their current state, gradients are actually a hot mess. The reality?

  • The specification is still in flux.
  • Full gradient support is not available in all modern browsers. (For now, Opera 11 only supports linear gradients.)
  • Many older, though relatively recent versions of browsers (Internet Explorer 8 & 9, Opera 10 Desktop, Opera Mobile, and Opera Mini, for example) don’t suport CSS gradients at all.

So, how can developers take advantage of gradients and still support older browsers? Let’s look at some approaches.

Set a background color

Take a look at the following CSS:

#linear{
    width:400px;
    height:300px;
    background-image: -moz-linear-gradient(top left, #f60 0%, #c09 50%, #fc0 100%);
    background-image: -webkit-gradient(linear, 0% 0%, 100% 100%, from(#f60), to(#fc0), color-stop(0.5,#c09) );
    background-image: -o-linear-gradient(top left, #f60 0%, #c09 50%, #fc0 100%);
}

This is a fairly common scenario. The developer (*cough*me*cough*) covered most of her bases, but forgot one: browsers that don’t support gradients at all. You can see what this looks like in Internet Explorer 9 (see Figure 1).

What a gradient looks like in Internet Explorer 9

Figure 1. Internet Explorer 9 doesn’t yet support CSS gradients. This is what it looks like if you don’t supply a background color.

Now look at the following CSS:

#linear{
    width:400px;
    height:300px;
    background-color: #333;
    background-image: -moz-linear-gradient(top left, #f60 0%, #c09 50%, #fc0 100%);
    background-image: -webkit-gradient(linear, 0% 0%, 100% 100%, from(#f60), to(#fc0), color-stop(0.5,#c09) );
    background-image: -o-linear-gradient(top left, #f60 0%, #c09 50%, #fc0 100%);
}

Here we’ve set a background image, but we’ve also set a background color. Browsers that don’t support CSS gradients will ignore the last three lines. (Note: each browser also ignores the other browsers’ vendor-specific prefixes.)

Setting a background color is the easiest fall back for older / less modern browsers.

Set a background image using an external file

Consider the following CSS.

#linear{
    width:400px;
    height:300px;
    background-image: url(migas.jpg);
    background-image: -moz-linear-gradient(top left, #f60 0%, #c09 50%, #fc0 100%);
    background-image: -webkit-gradient(linear, 0% 0%, 100% 100%, from(#f60), to(#fc0), color-stop(0.5,#c09) );
    background-image: -o-linear-gradient(top left, #f60 0%, #c09 50%, #fc0 100%);
}

In this example, we’re taking advantage of how browsers apply the cascade. As it turns out, Opera 11, Chrome whatever-the-heck-version-it’s-up-to, and Firefox 4 will not make the HTTP request for the external file. Safari, however, does (see Figure 2). Internet Explorer 9 (and less-modern browsers) will only load the external file. Depending on your audience, this may be an acceptable alternative.

Safari web inspector

Figure 2. Safari downloads all images. Click to embiggen.

Note: I have just barely tested this in mobile browsers. (Opera Mobile 11 doesn’t support gradients. Users will see the external image).

Use SVG gradients to create a background image

Internet Explorer 9 and Opera 10 (including Mobile) do not support CSS gradients. They do, however, both support the use of SVG images as background images. Another alternative to using external images, then, is to use an SVG file.

#linear{
    width:400px;
    height:300px;
    background-image: url(gradient.gif);
    background-image: url(gradient.svg);
}

This example works in all current desktop browsers, and most mobile browsers. Safari 5, again, will download both images. Most others will download the latter SVG image. The advantages here are clarity and (arguably) ease of maintenance. Want a different gradient? Change the images.

You should be aware, though, that some recent(-ish) versions of mobile WebKit — such as the T-Mobile myTouch 4G browser — don’t support SVG backgrounds. You’ll still need to add a linear gradient for those browsers, or set a background color.

Or keep doing what we’ve been doing

Of course, the growth of SVG and CSS gradients support doesn’t preclude using GIF, PNG or JPG gradients. The biggest point in favor of using bitmap images is that they still work in older browsers and current ones.

As with any aspect of web development, the right approach should balance concerns of maintainability, file size, and the browser distribution of your audience.

You left out linear-gradient!

I left it out of the examples above for two reasons: (1) simplicity; and (2) the syntax could change (though if I had to predict, it won’t change by much). Be forward-thinking! There are very few reasons not to include the proposed linear-gradient syntax in your code.

  • http://twitter.com/grwebguy Bill Creswell

    In their own proprietary way, IE supported gradients long before FF, Webkit.
    http://www.colorzilla.com/gradient-editor/ is a great way to generate cross browser gradients.

  • http://twitter.com/IDIUX Iain Dowling

    Great article. Just thought it might be worth mentioning the option of using a gradient SVG image represented as a data URI within your CSS, for browsers such as IE9 and Opera. You could use conditional comments for IE9 and browser sniffing for Opera, then feed them the alternative CSS along the lines of:
    #linear { background-image: url(data:image/svg+xml,##SVG converted to base64 code; }

    The best image-to-data-URI converter I’ve found is here:
    http://www.scalora.org/projects/uriencoder/

    You get the advantages of the lack of an additional HTTP request for an image resource, plus I’ve had problems before with servers dictating the incorrect MIME types for SVG and therefore the browser refusing to render them, which this solution side-steps.

  • Anonymous

    Good point Iain. Thank you!