A List Apart

Menu

Super-Easy Blendy Backgrounds

Issue № 227

Super-Easy Blendy Backgrounds

by Published in CSS, HTML · 63 Comments

A note from the editors: This article, while brilliant for its time, is now outdated. (Use CSS3 gradients instead.)

Recently, while trying to implement a few different navigation ideas that a designer had thrown my way, I became frustrated with my weak image editing skills.  The design was gradient-heavy, so a traditional approach to navigation markup and styling would require a dozen or so background-image slices to meet the varying colors and height requirements.

After spending a mortifying amount of time creating the images—I’m a programmer by trade, so anything more complicated than MS Paint gives me the willies—I had to take a step back and figure out a better way.  What if, after finishing, I needed to tweak the height?  Or, God forbid, the color palette?  My head was going to explode if I had to open an image editor again, so the Super Easy Blendy Backgrounds technique was born.

The blendy way

Almost all the gradients in the design given to me were blended to white, so I figured that if I created a PNG that was blended from transparent to white, I could use the PNG as a background image and rely on the background-color style to provide the other half of the blend.

I fired up my trusty image editor and fumbled around until I had created two PNG images: a 100×100 px white-to-transparent blend, and a 100×100 px black-to-transparent blend. (I didn’t need the black for this application, but I wanted to see what it would look like.)

Two transparent blends (white-to-transparent and black-to-transparent)

My two transparent-blend images, built in The Gimp

Using those images, I quickly threw together the CSS, and voila!  Beautiful blendy backgrounds. (IE6 users, hang on; we’ll get it working for you, we promise.)

Here’s the CSS:

.blue { 
  background-color: #2382a1; 
}
.green { 
  background-color: #4be22d; 
}
.pink { 
  background-color: #ff009d;
}
.gradwhite {
  background-image: url(grad_white.png);
}
.gradblack {
  background-image: url(grad_black.png);
}
.box {
  border: solid orange 2px;
  float: left;
  height: 100px;
  margin: 1px;
  width: 175px;
}

Here’s the markup:

<div class="box gradwhite blue"></div>
<div class="box gradwhite green"></div>
<div class="box gradwhite pink"></div>
<div class="box gradblack blue"></div>
<div class="box gradblack green"></div>
<div class="box gradblack pink"></div>

In this example and those that follow, we’re using color-based style definitions to make the example easier to understand—but we all know not to use presentation-specific words in our actual class names, right? Right.

Here’s example one, which produces this result:

Example of PNG gradient used as a background

A PNG gradient used as a background

Hey, it’s not scaling!

After giving myself a congratulatory pat on the back, I tried to scale that div to the size that I wanted.  And, as you’ve probably already figured out, the background gradient didn’t scale. Argh! I could force the background image to repeat horizontally or vertically (using repeat-x or repeat-y), but there was no way to scale the background. (See example two if you want to feel the pain.)

CSS3 is going to implement a background-size attribute, but since CSS3 has an ETA of never, that’s no help now. So what do we do?  Well, we use something that will scale, like the img element.  Instead of using a background to display the PNG blend, we can use an img element, and set the width and the height to 100%.

You can check it out in example three, which produces this result:

Six PNG gradients that scale with their parent elements.

Successful scaling—woohoo!

Here’s the new CSS (overwriting what we had before):

.blue { 
  background-color: #2382a1; 
}
.green { 
  background-color: #4be22d; 
}
.pink { 
  background-color: #ff009d;
}
.gradwhite img, .gradblack img {
  background-color: transparent;
  height: 100%;
  left: 0px;
  position: absolute;
  top: 0px;
  width: 100%;
}
.box2 {
  border: solid orange 2px;
  float: left;
  height: 150px;
  margin: 1px;
  position:relative;
  width: 84px;
}

Here’s the markup:

<div class="box2 gradwhite blue">
  <img src="/grad_white.png"/>
</div>
<div class="box2 gradwhite green">  
  <img src="/grad_white.png"/>
</div>
<div class="box2 gradwhite pink">
  <img src="/grad_white.png"/>
</div>
<div class="box2 gradblack blue">
  <img src="/grad_black.png"/></div>
<div class="box2 gradblack green">
  <img src="/grad_black.png"/>
</div>
<div class="box2 gradblack pink">
  <img src="/grad_black.png"/>
</div>

The image is showing up on top of my text! What gives?

Now that we have these sweet blendy backgrounds, let’s try to put some text in them. The first thing we need to do is make the boxes scale when the user resizes the text. We’ll do that by dropping the height declaration and then adding a conditional comment as a favor to IE7, which apparently looks to the parent element for a height if none is specified. You can read more about conditional comments at Quirksmode.

Note: In real life, you’d probably want to simply include a CSS file that targets a compliant browser like Firefox and then include two more (using conditional comments that target IE6 and IE7). But for now, here’s that comment:

<!--[if IE 7]>
<style type="text/css">.box {
  border: solid red 2px;
  height:2.5em;
}
</style>
<![endif]-->

Example of the text partly obscured by the PNG gradient.

Text showing up behind the PNG gradient

You can follow the attempt in progress in example four. The absolutely positioned image is showing up in front of the text. To correct that, we use the universal selector to select any descendents of .gradwhite, position them relatively (greater specificity could, of course, override this as necessary), and give them a z-index of 1. Giving the img a z-index of 0 then keeps it from popping to the surface. While we’re at it, we’ll add a little style to the paragraphs to set them off.

Example of text showing up in front of a PNG gradient.

Text correctly appearing in front of the PNG gradient

Example five does the trick. Here’re the new and updated rules:

.gradwhite img, .gradblack img {
  height: 100%;
  left: 0px;
  position: absolute;
  top: 0px;
  width: 100%;
  z-index:0;
}
.gradwhite * {
  position: relative;
  z-index: 1;
}
.gradwhite p {
  margin: 0px;
  padding: 3px;
}
.box3 {
  border: solid orange 2px;
  float: left;
  margin: 1px;
  padding: 5px;
  position:relative;
  width: 256px;
}

And here’s the markup:

<div class="box3 gradwhite pink">
  <img src="/grad_white.png"/>
  <p>This text is in front of the image.</p>
</div>

Do you realize none of this works in IE6?

We all know that IE6 and prior versions don’t support PNG transparencies.  And since IE7 won’t have the majority market share for awhile, you’re probably thinking that this is a great exercise in something your boss will never let you use, right?  Well, IE has this great little thing called the AlphaImageLoader filter, which is explained in ALA’s “Cross-Browser Variable Opacity with PNG: A Real Solution.” The pertinent part is that you can load a PNG image and set the filter to “scale,” thus eliminating (for IE) the need for the workarounds we used for Firefox.

So how do we make this work in both IE and Firefox at the same time?  Well, we can target our styles for Firefox, and then use the star-HTML hack to override them for IE6. I’m using the star-CSS hack here more in the interest of clarity than anything else; I think it helps to see everything together, plus it’s easier to cut and paste. When I use this technique in a production environment, I prefer to use conditional comments to target browsers. After all, hacks are hacks, and they aren’t guaranteed to work in perpetuity.

Text showing up in front of the PNG background.

Technique working in IE6

Example six puts it all together. Here’s the CSS to add. (Line wraps marked » —Ed.)

.gradwhite {
  filter: progid:DXImageTransform.Microsoft. »
AlphaImageLoader(src='grad_white.png', »
sizingMethod='scale');
}
* html .gradwhite img {
  display:none;
}

And here’s the markup. (Don’t stare too long at the ugly inline styles—they’ll be gone in just a second.)

<div class="box gradwhite pink">
    <p>Wow, maybe this will actually work!
    </p>
</div>

Wrapping everything up

Finally, we’ll add one more star-HTML rule (position:static applied to the box class) to deal with a nasty IE6 bug that keeps links from working with AlphaImageLoader in certain circumstances.

Example seven shows our final cross-browser Super-Easy Blendy backgrounds, which look like this:

Gradient boxes containing linked text

Super-easy blendys in all their glory

Here’s the final CSS in its entirety. (Line wraps marked » —Ed.)

<style type="text/css">.grad img {
  height: 100%;
  left: 0px;
  position: absolute;
  top: 0px;
  width: 100%;
  z-index: 0;
}
.box {
  border: solid orange 2px;
  float: left;
  margin: 1px;
  position: relative;
  width: 165px;
  padding: 5px;
}
.box * {
  margin: 0px;
  position: relative;
  z-index: 1;
}
* html .grad {
  filter: progid:DXImageTransform.Microsoft.AlphaImage »
Loader (src='grad_white.png', sizingMethod='scale');
}
* html .grad img {
  display: none;
}
* html .box {
    position:static;
}
.blue { 
  background-color: #2382a1; 
}
.green { 
  background-color: #4be22d; 
}
.pink { 
  background-color: #ff009d;
}
</style><!--[if IE 7]>
<style type="text/css">
.box {
  border: solid red 2px;
  height:2.5em;
}
</style>
<![endif]-->

The final markup:

<div class="box grad blue">
  <img src="grad_white.png" alt="blur gradient box" />
  <p><a href="#">Ooo, linked text</a>!</p></div>
<div class="box grad pink">
  <img src="grad_white.png" alt="pink gradient box" />
  <p><a href="#">Ooo, linked text!

</div>
<div class="box grad green">
<img src="grad_white.png" alt="green gradient box" />
<p><a href="#">Ooo, linked text</a>!</p>
</div>

That’s it! In Part Two of this two-part series, I’ll explain how to work this technique into visually sophisticated layouts.

About the Author

63 Reader Comments

Load Comments