Multiple Backgrounds and CSS Gradients

CSS3 features are making their way into the various browsers and while many are holding off on implementing them, there are those who are venturing ahead and likely running into a world of interesting quirks across the various platforms.

Two such features that I have been having the pleasure of enjoying are the use of multiple backgrounds and CSS gradients. I'm covering both features because multiple backgrounds by itself is simple enough, as are CSS gradients, but combining the two is where things get interesting.

Multiple Backgrounds

What are multiple backgrounds when it comes to CSS? I mean the ability to define more than one background image for a single element. That sounds wonderful, doesn't it? It is. No more having to have nested elements with lots of CSS just to create a layered effect. The syntax is very straightforward: just separate each background image with a comma.

background-image: url(…), url(…);

For browsers that don't recognize multiple backgrounds, the entire background declaration will be ignored. (Actually, according to PPK, Explorer Mac will show the last background declared.) Depending on your design, you may need a single image declared and then declare the multiple background on the next line.

background: url(…) 0 0 repeat 10px 100px, url(…) 5px 5px no-repeat 5px 5px #FFF;
background-image: url(…), url(…);

You can declare multiple backgrounds using the shorthand syntax, as well.

background: url(…) 0 0 repeat, url(…) 5px 5px no-repeat #FFF;

I threw a bunch of stuff in here to see if you're paying attention. The shorthand syntax for a normal background includes image, position, and repeat. However, the colour is always the last thing declared. (I've traditionally always declared it first.) There can only be one colour applied to an element—although with rgba, if you could declare the colour more than once, it'd theoretically be possible to mix colours.

Background Size

Another interesting property that is being implemented in recent browsers is support for background size. Any browser that supports multiple backgrounds also supports background size.

When declaring background size for multiple backgrounds, the declarations are separated by commas just like with background-image.

background-image: url(…), url(…);
background-size: 10px 100px, 5px 5px

In Opera, Mozilla, and Safari, you'll need to declare the vendor prefixes. Chrome and the Opera 10.5 dev builds don't require the vendor prefix. And to further clarify, background-size support is in Opera 10.1 but multiple background support isn't.

-o-background-size: 10px 100px; 
-moz-background-size: 10px 100px, 5px 5px;
-webkit-background-size: 10px 100px, 5px 5px;

(As much as I love the features that browsers are implementing, I'm getting really annoyed at all the vendor prefixes. Seriously. And believe me, by the end of this article you'll see how much worse it can get.)

The background size declares width first and then height. Technically, you should be able to omit the second value, which should use auto for the second value.

background-size: 10px; /* should be the same as '10px auto' */
background-size: 100%; /* should be the same as '100% auto' */

The reality?

Opera 10.5 Works according to the spec
Safari 4 ignores the declaration altogether
Firefox 3.6 Works according to the spec
Chrome 4 Treats the second value as the same as the first. Eg: 10px becomes '10px 10px'

There are two other values that can be used for background-size: contain and cover. Cover will make sure that the background image covers the element. Contain makes sure that the entire background image is visible within the element. Only Safari seems to be the odd man out on this one.

If you declare multiple images using the shorthand syntax, the background size is always declared after the background position (since they could technically be confused with each other) and separated with a slash.

background: url(…) 0 0 / 10px 100px repeat, url(…) 5px 5px / 5px 5px no-repeat #FFF;

The only problem is that no browser supports this and the entire background declaration will be thrown out if you try and use this syntax. Well, except for Opera 10.5 which does a weird thing where it ignores just the parts of the declaration it doesn't understand.

All this to say that you must always declare background size using the long form. In my opinion, this will almost likely always be the case... changing background implementations risk backwards compatibility and that's a hell I'd like to avoid.

CSS Gradients

One of the many cool CSS additions to come out of Webkit is the ability to specify gradients. Whereever you would normally specify an image using a url() syntax, you can specify -webkit-gradient instead. Probably the most likely scenario will be for background images but you could use it for border-image or list-style-image, too.

background-image: -webkit-gradient(linear, 0 top, 0 bottom, from(#496178), to(#2E4960));

The syntax takes a gradient type as the first parameter: linear or radial. The next two values indicate the start and stop points of the gradient. Each parameter after that is a color-stop(x, y) function where x is a percentage or a value between 0 and 1 and y is the colour value. from and to are shortcuts for color-stop(0, y) and color-stop(1, y) respectively. This implementation mirrors the functionality within the canvas specification.

CSS gradients have made their way into the W3C as a draft spec, although the syntax is different from how Webkit has implemented it. Firefox 3.6 has just been released and now includes CSS gradients using this newer syntax which separates the two types of gradients into their own syntax: -moz-linear-gradient and -moz-radial-gradient.

background-image: -moz-linear-gradient(90deg, #496178, #2E4960);

The first parameter is the position or angle. There are a number of ways that the shorthand can be calculated and degrees are likely the easiest to use. If you're doing a gradient from top to bottom, the angle can be ignored altogether and the colour stops are all that need to be specified.

background-image: -moz-linear-gradient(#496178, #2E4960);

There's no need to specify the color-stop, from or to functions like with the webkit gradients. You can specify multiple colour stops and it'll create a gradient between each one. If you wish to adjust the position of where the gradient transitions, you can specify it as a second value with the color stop.

background-image: -moz-linear-gradient(#496178, #323232 20%, #2E4960);

You can also use rgba values, too, if you wanted to create semi-opaque gradients.

Mixing the Ingredients

Now that you know how the two things work, let's look at putting it all together. If you want to do multiple backgrounds and use CSS gradients, you'll need to do something like the following:

background-image: url(…);
background-image: url(…), -webkit-gradient(linear, 0 0, 0 100%, from(#FFF), to(#000));
background-image: url(…), -moz-linear-gradient(#FFF, #000);
background-size: 10px 100px, 5px 5px;
-o-background-size: 10px 100px;
-moz-background-size: 10px 100px, 5px, 5px;
-webkit-background-size: 10px 100px, 5px 5px;

Remember when I said the other browsers ignore the entire declaration? That's right, if Firefox doesn't like -webkit-gradient (because it has no clue what it is), it'll pretend that the entire background shorthand was never declared. Opera 10.5 alpha will still recognize any url() declarations and just ignore the -webkit-gradient and -moz-linear-gradient statements. I've put in a bug report with Opera to change their behaviour to match what the other browsers do in this situation.

I'm also going to take a moment right now and rant about vendor prefixes. Yes, I know I mentioned it before but this is getting absurd. Honestly, my plea to Microsoft is to avoid jumping on this CSS3 bandwagon until specifications settle. Where they have, nail it to a tee and make sure it matches how other browsers do it. Don't be innovative.

Wrapping it up

Having been working with CSS gradients as of late, I really wanted to document the current state of things. As you can see, some features can offer up a bumpy ride when you want cross-browser compatibility (even if we are still ignoring the elephant in the room: Internet Explorer).

Check out the Demo Page

Published February 01, 2010
Categorized as HTML and CSS
Short URL: https://snook.ca/s/969

Conversation

46 Comments · RSS feed
ADrian said on January 31, 2010

Interesting and helpfull article, thank you.

Brendan Falkowski said on January 31, 2010

Nice digging expedition. Vendor extensions compounding CSS attributes are starting to worry me a bit too. It's becoming more difficult to write readable single-line CSS (another debate) let alone declarations that don't trip on each other.

Thinking the W3C should standardize on a 2/3 majority of CSS3 syntax implementations and publish the spec. It wouldn't affect IE since it ignores them and shows up late to every party (inappropriately dressed).

The WebKit, Mozilla, Opera, and Konquerer teams aren't suddenly going to rewrite their interpretations over their extensions and break existing uses. Unless I'm missing a major vender, why not finalize border-radius and kin so we can progressively degrade -moz/-webkit/-o/-khtml?

choen said on January 31, 2010

The existence of CSS3 will reduce the use of the image. I tried "-moz-linear-gradient (# 222, # 000)" but in IE does not come out the color, whether there are ways that color may be just # 222 in IE. thanks before.

Cesar said on February 01, 2010

Just skimming this article gave me a headache, I'll just wait until the war settles down...never-the-less, that was a great article snook.

Peter van der Zee said on February 01, 2010

Didn't know about multiple background support, thanks. This will certainly help removing the styling cruft required right now.

Brad Koehler said on February 01, 2010

Thanks for a great intro to these two.

Will the vendor prefixes be dropped when the spec is finalised?

Jonathan Snook said on February 01, 2010

@Brendan Falkowski: You'll be happy to know that border-radius is likely to be one of the first properties to see vendor prefixes dropped. Opera has dropped it and it looks like IE9 won't use a vendor prefix. I expect Firefox to be next. Chrome and Safari should resolve how it handles border transitions to match the other browsers before dropping the prefix.

@Choen: Since IE doesn't recognize -moz-linear-gradient, you need to put any IE (or any browser that doesn't support multi-background) onto its own line like this:

background: #222;
background: -moz-linear-gradient(…);

@Brad Koehler: They most certainly will. In a few years, we can expect the specifications to be finalized and all the browsers to shift to matching the spec and dropping the vendor prefixes. I long for that day. :)

Ape Web said on February 01, 2010

I would like to see a demo of this if anybody has an interesting demo to view?

FP said on February 01, 2010

In the background-size section where you mention how a browser should deal with only a single value I think you might be looking at an older version of the spec, in the December 2009 version it says:

If only one value is given the second is assumed to be ‘auto’.

So I think that both Firefox and Opera are correctly handling this situation.

Jonathan Snook said on February 01, 2010

@Ape Web: I've updated the article to include a link to a demo page.

@FP: thanks for pointing that out. I've updated the article to properly reflect that.

bingeboy said on February 01, 2010

Snook this is a great post. Thanks!

iammikek said on February 01, 2010

on your demo, theres quite a bit of discrepancy between firefox3.6 and safari4.0.4 on snow leopard. cover snd contain look the same. should i upgrade to new webkit to see what you are seeing?

George Terezakis said on February 01, 2010

I was quite amazed to see that Safari and Chrome can in some cases interpret css differently! (the one background-size value case)

Alex @BaldMan) said on February 01, 2010

Wow, thanks for posting this Jonathan. Even with the vendor extensions and the fact that we won't be able to use these attributes to the fullest for a while, it's exciting to see what is possible. This post has sparked a couple of ideas in my head for a personal experiment or two, which is the ideal way to kick off a week. Your work and sharing are appreciated given the herculean task of sorting this out.

Adriaan said on February 01, 2010

With linear gradients the difference in syntax between moz and webkit browsers is really annoying...so after a bit of googling, I found this really helpful site to get the basics right http://gradients.glrzad.com/

Thanks for a good quality post, I found it really enlightening after delving into CSS gradient backgrounds myself during the last couple of weeks.

Matt Wiebe said on February 01, 2010

Thanks for getting in the trenches and sharing your findings.

Interesting that WebKit doesn't support the contain or cover keywords in background-size.

Jonathan Snook said on February 01, 2010

@iammikek: FF3.6 and Safari 4.0.4 are rendering cover and contain the same? Odd. I'm on FF3.6 and Safari 4.0.4 (on Snow Leopard) and Firefox renders them as expected whereas Safari doesn't.

kevadamson said on February 01, 2010

Nice article. I've just been playing with multiple backgrounds and gradient combos all day for a project, and one thing I thought I may be able to do is have a transition between one gradient and another (on :hover). Doesn't seem to be able to be done at present? Anyone know if this is the case?

Wolf said on February 01, 2010

Do note that IE supports gradients, albeit in an awkard way. E.g. try this rule:

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

Wolf said on February 01, 2010

Uhm sorry that last one was not a gradient but will work like rgba(0,0,0,0.7). Ty changing the last six 0's to a different color value to see a gradient.

philippe said on February 02, 2010

You should try WebKit (mac) nightlies (and Chrome 4+) while dropping the -webkit- vendor prefix. WebKit is then very close to spec, except for background-repeat: space (or round), treated as no-repeat. Opera 10.5a is wrong on that one too, afaict.
A bunch of my testcases.

Thomas said on February 02, 2010

@Jonathan: Thanks for the great overview in your post!

@APE WEB: Jonathan's post inspired me to play with multiple backgrounds - here are examples for simple multiple background usage and also for JavaScript animations using multiple backgrounds: http://www.storiesinflight.com/html5/backgrounds.html

Ron said on February 03, 2010

will all this work in IE ?

Ape Web said on February 03, 2010

Hey, thanks for the examples, I was looking in Firefox stupidly and seen nothing but normal pictures (Jonathan) and blue backgrounds (Thomas) but I realised pretty soon that it is probably that my version of Firefox does not support this kind of CSS despite the vendor prefix -moz which seems to be ignored. (Firefox 3.5.7)

I took a look in Chrome and saw some interesting results (Jonathan) and some potentially useful results (Thomas). I had never heard of using multiple CSS backgrounds and things as I am too busy doing commercial work and don't work in the research and development department although I will be passing on the details.

I expect sometime in the future somebody will come up with a JavaScript fix to allow multiple backgrounds in some way or another to allow some graceful degrading as I don't think 1 background by itself is comparable to multiple backgrounds that need each other to work.

On the other hand, I have wanted something that allows me to apply multiple backgrounds to a layer for some time as it can be tricky to write semantic XHTML while achieving everything the designer has came up with.

Rajasekhar said on February 03, 2010

will all this work in IE ? and windows browsers? please let me know this.... waiting for ur response snook and ur effort is great

Matt Wiebe said on February 03, 2010

I'll step in and answer for Mr. Snook: no, this will not work in IE.

Gradients work in Safari 4 and Firefox 3.6.

Thomas said on February 03, 2010

Wow! I can't wait to see this working in all major browsers. Will be a great step forward!

me said on February 03, 2010

We waste alot of time with ie6 hacks for some people who "don't feel the need of upgrade" they dont't know how much we work just so they can see our site's in ie 6

Onderhond said on February 03, 2010

>> I'm also going to take a moment right now and rant about vendor prefixes.

Hear hear!!

Thomas said on February 04, 2010

@APE WEB: Elements with multiple background images are supported in Firefox 3.6, Safari 4.0.4 and in the latest version of Chrome. Firefox 3.5.x as well as IE don't support this feature - and in the case of IE we will at least have to wait for IE9.

Matthias Willerich said on February 04, 2010

But Jonathan, surely you'd want it mentioned somewhere that vendor prefixes are A Good Thing? :-)

I can vividly feel your pain during this transition period, but it's better than browsers attempting an implementation at one or the other CSS feature, fail at following the specs, and then you'd end up with a single rule that is interpreted differently across browsers. That's where all those underscore and funky comments hacks came from, no? Your background-size example somewhat proves my point: Chrome shouldn't have picked up the non-prefixed rule until they get it right (although I guess it doesn't hurt to explicitly specify both dimensions), and it's definitely good that the different approaches to gradients aren't using the fully fledged rule, as it could never work cross-browser as of now.

And with regards to you not wanting IE to be innovative: This is only down to their rare releases, right?
I mean, we're excited about all other browsers' innovations, want to use it in production while it's still smoking hot, and of course equally want browser vendors to compare notes of how they interpret the specs, and, once they support the real rule, all do the same thing across the board. If IE was releasing CSS rendering changes every few months or so, we'd love them to come up with experimental (prefixed!) implementations of every draft css rule we can think of, right?

Theo said on February 05, 2010

Even if all this stuff is not widely supported (will it ever be ?) is good to learn/now/use it, so thank you for this post. Bookmarked

Ape Web said on February 09, 2010

In most cases, people over do the nested divs. I go for a minimalistic and semantic approach when using divs and think others should follow this approach, and if the designer comes up with something snazzy then find a way of making the design work without bloating the page.

Although, saying that, this will not always be possible and therefore multiple CSS backgrounds will be very useful. Just because multiple CSS backgrounds will one day be supported, I think we should all stick to our roots and try and create semantic HTML first and worry about the CSS later.

Paul said on February 11, 2010

It's the first time I've read something about these Multiple Backgrounds. Very interesting. Thank you!

Oliver Cardiff said on February 11, 2010

I had a look at these features of CSS3 a while ago and would really like to use them on websites that I design but the only thing stopping me is IE as it doesn't support any CSS3 as of yet.

These are definitely good features and maybe I can use them on my personal site. Thanks for sharing this information.

Andrija Markovic said on February 16, 2010

Yep, one day this will all be very nice, hope that day comes soon...

Krishna said on February 24, 2010

a great read....really interesting!
I cant wait to use these new techniques soon. I just hope the dust settles with all the different requirements for different browsers...

thanks for sharing!

thinsoldier said on February 24, 2010

Thanks.

Have you tried simulating Photoshop's Gradient-Stroke with just css and without using a wrapping div?

I tried but haven't gotten very far:
http://thinsoldier.com/csswishlist/examples/1.php

Tab Atkins said on February 25, 2010

Matthias Willerich has it right - vendor prefixes are a Good Thing, as long as they continue being used as they currently are, as a way to do early experimentation with new features.

If browser vendors didn't use prefixes, we'd be in *tons* of trouble when some particular browser's impl gets popular but then we want to change the spec. Frankly, we'd be unable to. It would freeze mistakes in time forever.

A vendor prefix at least means that you know what you're getting into when you use it on your page. It's early, it's experimental, it might change before being finalized and losing the prefix. In the meantime, you can play with it and see if it meets your needs, and potentially get the spec changed if it's not good enough.

The whole situation does get confusing when there *is* significant change between implementations, I'll admit. The differences in webkit and mozilla-prefixed gradients make them pretty weird to work with right now. But that's because webkit came out first with an experimental implementation, I thought it sucked and wrote a new syntax that made its way into the Images module, and mozilla implemented the new one in the spec. It still might change *slightly* before we take Images to CR (which is the point at which it is appropriate to drop the prefix), but all the simple uses of -moz-*-gradient() should continue to be correct until the standard is finished.

That all said, good post! I just added Moz-style gradients to my company's site template, so you can see them used in action at http://www.igofigure.com. It's astonishing how much you can speed up a page load by swapping images of gradients for CSS-specified ones.

Scott Gale said on February 28, 2010

I have been researching how these pieces can create clean text rendering. This article was informative. I'm hoping to leverage CSS3 gradients and a 1px stroke to create text effects usually only relegated to Photoshop and sIFR.

Brendon Kozlowski said on March 18, 2010

Thank you for your tips here, Jonathan! The WebKit team's descriptions of gradient just was not as easy to comprehend and understand as yours. I now believe I actually understand the parameters that I'm using thanks to this blog post. Much appreciated!

Weetreuttom said on February 10, 2011

I'm really Glad i ran across this site.Added snook.ca to my bookmark!

rajkamal said on February 25, 2011

Thanks for the excellent post.

p.bgTest{
width:300px;
height:250px;
margin-left:10px;

background:url(acceldom.jpg) 10px 5px no-repeat ,
url(Examples.gif) right 5px no-repeat,-webkit-gradient(linear, 0 0, 0 100%, color-stop(0,rgba(0,0,0,0)), color-stop(1,rgba(0,0,0,1))) 0px 0px no-repeat;
background-size:180px 250px, 20px 20px 10px 10px;
}

i was expecting the last gradient, to be of 10X10 size. But the gradient was spearding the whole paragraph.

joshbot  said on March 30, 2011

Your "background-size: cover" tip ended days of frustration. Thank you VERY much.

Maurice said on April 19, 2011

This is an absolutely fantastic walk through. You just saved me a tone of work and extra lines of z-indexing for floaded div's and all sorts of ****.

Great, GREAT demos as well.

monochrom said on May 16, 2011

Hello There. Thanks very much for your article, very useful information! I'm dealing with gradients and background-images at the moment. I was wondering if its possible to combine these two, and YES it is :) Thank you!

Sorry, comments are closed for this post. If you have any further questions or comments, feel free to send them to me directly.