Nov 30 2011

Color-independent CSS with alpha overlays

Category: Software,WebdevelopmentSpiller @ 00:07

This sidebar design caught my eye:

There are several of these boxes in different colors and I kinda liked the effect. To create this effect two images are used, one which contains the top part of the box, including the rounded corners and another which just contains the rounded corners for the bottom. (These needs to be separated so that the box can grow.)

However for each color there are a separate set of images and you have to set the color in the CSS too. This requires you to download several almost identical images to view the page which is not optimal. Secondly, in the case you want to change the color, you need to create a new set of images and then find the part in the CSS and change that too. If you wanted to mirror the boxes or change the design a little bit, you would have to redo every image, which again is not optimal.

So the optimal solution would be that the implementation didn’t rely on a specific color and that we could just change the color in the CSS and expect everything to work as intended. And this is indeed possible in this case. We can even use CSS3 transformation to change the color on-the-fly!

Color independent implementation

The trick here is to use alpha compositing to create the effect. If we placed a completely white image on top of the orange color, we would obviously end up with an completely white result. However what if the image had been 50% transparent? Then we would have ended up with a lighter orange color since some of it had been replaced with white.

This is exactly the effect we are going to exploit here. With image formats like PNG you can control the alpha (transparency) of each pixel by drawing on the alpha channel. So we will make a completely white image and then draw the two circles on the alpha channel. Let’s start with looking on the original image:

Notice that it is saved in JPEG and weights 7.18 KB. As explained previously, this should have been saved in PNG as it compresses better. So I remade it from scratch, trying to match the original image.

Here is the image, where we have drawn on the alpha channel instead:

(I had to make it blue as otherwise it wouldn’t have been visible as this blog´s background is white.)

Since this image is completely the same color, just with alternating alpha values, it will work nicely with all backgrounds. Try it out on different backgrounds and see the effect! And take a look at the file size too, it is only 1.82 KB, quite a bit less than the original. (The white version was 1.85 KB)

Using CSS3, we can create our box as easily as this:

width: 223px:
min-height: 140px;
border-radius: 5px;
background-color:  #f07575; /* Some random color here */
   background-image: url('overlay.png'),
   -o-linear-gradient( top, rgba(0,0,0,0) 140px, rgba(255,255,255,0.41) 140px);

First we set the width and the minimal height (so that it can expand), nothing special here. Next up is creating the rounded corners and setting the background color we want.

The background-image is the interesting part. First we use the overlay image we just made for this. We have background-repeat set to no-repeat, so it only appears where we want it.

Then a gradient suddenly appear? This is to make it look as intended when the box becomes larger than the 140px the image is. If we didn’t do anything, this would happen:

So to avoid this we could make our overlay image as long as the box possible could be, for example 1024 pixels high. This would increase the file size a little (to 2.97 KB) so let’s use CSS3 to do it in a more fancy way.

Instead of using a single image, we could use two, our normal overlay and a second overlay 1024 pixels high which is fully transparent the first 140 pixels and then becomes our semi-transparent white colors afterwards that. If we place those two on top of each other (using CSS3 multiple backgrounds) we can replicate the combined image.

Why do this? Because we can make our browser generate the second image by exploiting linear-gradients. Linear gradients are pretty flexible, we can specify several color-stops and the positions those stops should be at. So lets take a look at that piece of CSS again:

-o-linear-gradient( top, rgba(0,0,0,0) 140px, rgba(255,255,255,0.41) 140px);

We start at the top with a fully transparent black which should continue to 140px. Then we change the color to a transparent white, which should start at 140px. Our two colors start and stop at the same place, so we are actually not getting a gradient as the switch is instantaneously. However what we do get is the image we want, and it will automatically expand to even more than 1024 pixel if required.

The sample page ends up looking like this:

CSS2 implementation

The only part I will cover here is how to make the rounded corners color-independent. Download the sample page to see the full implementation.

Adding rounded corners so they don’t depend on the color of the box is pretty simple, just draw the inverted corner so that you draw the page background. This will of cause make it dependent on the background of the page, but it is better than it being dependent on both, right?

(Again in blue because of the blog theme.)

Sample page download

You can download the images and HTML+CSS2/3 source here:

The file css2.html contains the CSS2 implementation and the file css3.html contains the CSS3 implementation. The CSS3 implementation also contains a little extra stuff to make it fall-back more gracefully.


Leave a Reply