transparent corners / context-independent fun

My previous article showed you how to implement a simple and minimal rounded corner effect. This week I'll show you a different trick, hardly as elegant or simple as the former, but still useful when all other options are failing. This article is about creating context-independent irregular corners. Quite a mouthful indeed.

Using solid images for irregular corners (think rounded corners) is fine, as long as you can predict the background color on the outside of the edge of the box. But mind that you cannot use transparency in your images as the background color of the box will spill through, destroying the intended effect. I know that css3 provides a solution for rounded corners, but not every irregular corner is a rounded corner. What if you need corners cut off at 45°? Even if future css could handle that, there's still an almost unlimited amount of irregular shapes you could create that wouldn't fit any spec out there.

In many cases the context of a box is known. Even when it crosses a diagonal gradient you can still cut the gradient into the corner images. It's a bitch to maintain (slight changes in widths/margins will influence the position of your box over a gradient), but ultimately it works. So what if you have a page overlay with irregular corners? You cannot possibly predict what will be underneath that, so it becomes impossible to cut the context into the images for the irregular corners.

finding a solution

As far as I know there is no elegant solution to this problem, but elegance is not always a key factor. There's a huge difference between "I cannot do it" and "it can be done, but it'll be dirty and time-consuming", especially when talking to project managers who demand results. And so I started looking for a solution that worked, not one that would revolutionize the world of css. If you start from there, it's actually quite easy to accomplish, you just need wrappers. Tons of wrappers.

One rule I set for myself was not to use any empty structural elements above, below or inside the box. Even though some people see wrappers divs as an equally dirty trick, at least they maintain structural integrity, while empty structural elements mess up the structural composition of your document.

the basics

/* the images */ .box {background:url("corner-1.gif") right bottom no-repeat;} .boxWrap1 {background:url("corner-2.gif") right top no-repeat;} .boxWrap2 {background:url("corner-3.gif") left bottom no-repeat;} .boxWrap3 {background:url("corner-4.gif") left top no-repeat;}

The key is to make sure there just isn't a background color behind any of the transparent images. We start by setting the four corners of the box. That leaves us a cross-shaped area in the middle to fill with the background color of the box.

As a little side note, I usually apply a strict order in placing background images. Bottom right corner first, then bottom left corner, top right corner and finally the top left corner. It doesn't matter much when you're restricting yourself to pure wrapper divs to apply said images, but if you're using structural elements part of the contents of the box (hX tags or footer tags) the bottom right corner is usually the hardest one to reach. That's why I apply it as quickly as possible.

Like I said, just a little side note. You don't even need to agree with the order I'm using here, but any strict order will increase predictability of code over time. Just make sure to set a standard, even if it's just for yourself.

Check out the first example on the test page.

the trick

/* the background color */ .boxWrap4 {margin:0px 8px; padding:8px 0px; background:#cc0;} .boxWrap5 {margin:0px -8px; background:#bb0; } /* ie fixes */ .boxWrap4 {zoom:1;} .boxWrap5 {zoom:1; position:relative;}

The difficult part is getting the background color in the remaining area of the box. First we apply a left and right margin the same width as the corner images, and a top and bottom padding the same height as the corner images. Giving a background color to this wrapper fills in the center area and the top and bottom strips between the corners. Next we apply the same background color and a negative left and right margin (same numbers as the margin defined on its parent), so we can fill in the remaining left and right strips between the corner.

If the width of the top and bottom corners differs, choose the widest of the two. Same goes for the height of left and right corners. And to make this work in IE, we need the typical fixes for negative margins. Nothing too complicated.

Check out the second example on the test page.

the finishing touch

/* the background color */ .boxWrap6 {float:left; width:100%; margin:-8px 0px;} .boxWrap7 {padding:5px;} /* ie6 fixes */ .boxWrap6 {position:relative; zoom:1; padding-right:16px;} .boxWrap7 {position:relative; zoom:1; margin-right:-16px;}

In most cases this should suffice. The only remaining problem is that the inner box doesn't span the complete surface of the outer box. If you have big corner images you could be losing a lot of valuable space. The design might even dictate that text should be appearing in the strips between the irregular corners. To fix that we need two extra wrappers. The first one is floated and given a negative top and bottom margin (same size as the padding defined by the heights of the corner images). We also need a width:100%; to make it span the whole box. The second wrapper adds the needed padding to push the most inner box (boxWrap7) away from the edge again. Because of the width:100% declaration on the floated wrapper, this needs to be placed on an extra wrapper, otherwise you'll mess up the widths.

ie6 doesn't like this though, and loses Xpx (X being the sum of the left and right margin) with the float. Adding Xpx padding on the float and crossing it again with a negative margin on the next wrapper fixes this. I'm sure there must be a more elegant way to do this, but nothing I tried worked so far. Please do share your thoughts and fixes.

Anyway, check out the final example on the test page. A border was added to illustrate the position of the most inner box.

conclusion

As you can see, elegant it is not. Many double declarations and computed values of paddings and margins. It's a pretty messy setup requiring 5 extra structural elements and a massive 7 if you want it perfectly controlled. On the other hand, if anyone knows better alternatives which are just as flexible (and using wrappers, not empty structural elements), do share!

In the end, the technique works, cross-browser and without too many hiccups. And even if you despise the use of so many extra wrappers, you can now tell your project manager you know of a way, you just don't like the implementation. Looks better on your CV, trust me.