Transparent custom corners and borders

Have you ever wanted to make a resizable box with rounded (or any shape) corners, custom borders, and a transparent shadow? Did you also want to do that without cluttering your markup with a bunch of non-semantic div elements? Now you can.

In June last year I wrote about a way of creating a Flexible box with custom corners and borders. While that method works, it needs some extra markup and has a few other limitations. This new technique uses no extra markup, allows the use of transparent images for the corners and borders, and has no restrictions on the background colour and margins of the elements within the main container. Skip right ahead and take a look at the final example if you can't wait.

Wanted: less markup, more transparency

What, no extra markup? That's right. One of my Predictions and hopes for 2005 was that we would see an increased use of sensible JavaScript. There's been plenty of that already this year, and I hope you'll agree that what I describe here belongs in that category.

The extra markup that is needed to get the corners and borders in place is removed from the HTML and instead inserted with JavaScript. Turn JavaScript off and the custom elements disappear, leaving a more basic looking box behind. Disable CSS and you get an unstyled document. Disable both and you get an unstyled document. You get the idea. No matter what, the content of the box should always be accessible.

To allow for the use of transparent images for the corners and borders, the CSS had to be changed a bit. It's easier to follow when you can see all the markup, so check the CSS only example for the HTML and CSS, including the markup that is inserted by the script in the final example.

Since an element's background properties also determine the surface colour or image of the element's padding, I had to use margins and relative positioning instead of the padding I originally used to put the images in place. If I were to use padding, the transparency of the images would cause some unwanted overlapping, as demonstrated in the CSS only + padding example.

Just like the old version, this box will expand to contain any amount of content vertically, will handle any text size, and can become very wide before the horizontal borders start breaking up. How much it will stretch horizontally depends on the width of the background image that contains the corners.

The IE Factor

There is of course one caveat to using PNG images with alpha transparency. It's well-known that current versions of Internet Explorer for Windows do not support it. But since IE7, due out in beta later this year, will, I think it's reasonable to start looking at ways that transparency can be used. Obviously you will need to consider older versions of IE/Win for several years to come, but there are ways to send different images to those browsers.

In these examples I've used conditional comments to send GIF images to Internet Explorer browsers with a version number lower than 7, so when IE7 comes along it will use the PNG images, just like other modern browsers. Until then, IE users will get something similar to the CSS only: IE version example. I hope that doesn't count as browser elitism ;-).

Image usage

Two images are used. First, box.png contains a complete box and is used for the corners and the horizontal borders. For the sake of this demo I’ve made it 1600 pixels wide. You may be able to get away with a narrower image, though it probably won't save you many bytes. The other image, borders.png, contains the vertical borders.

Why use a single, large image for the corners instead of several smaller ones? There are several reasons:

  • Splitting the image into a bunch (eight in this case – one for each corner plus the top and bottom borders) of smaller images may actually increase the total file size, depending on the look of the corners and borders.
  • To minimise the number of HTTP requests sent to the server.
  • Convenience. When changing the look of the borders and corners, replacing two files is faster than replacing eight files.

Of course you can keep using the extra markup if you like. It works and won't actually cause any problems. Well, except in IE/Mac, where the vertical borders don't show up. If you can figure out how to fix that, please let me know. I'm not spending any time on it though, with IE/Mac being dead and not even included in a default Mac OS X installation anymore. Besides, using the JavaScript method described next will take care of IE/Mac.

Out with the divs, in with the JS

Being a sucker for clean markup, I wrote a little bit of JavaScript to help me clean things up. The script inserts the extra div elements and changes the class name of the main container. Changing the class name is done to enable different styling depending on whether JavaScript is available or not.

I'm no JavaScript expert, so while working on the script I used a few code snippets from elsewhere instead of spending three weeks trying to come up with something that wouldn't work anyway. The createElement function that makes the script work with both HTML (served as text/html) and XHTML (served as text/html or application/xhtml+xml) was found in Simon Willison's post Javascript, the DOM and application/xhtml. The technique for wrapping the contents of an element in other elements was, incidentally, also found in one of Simon's articles: Rounded Corners with CSS and JavaScript. Thank you, Simon. Finally, if you recognise the addEvent script it's because it's one of Scott Andrew LePera's widely spread crossbrowser event handlers.

I just adapted the scripts as needed and made them work together. Study the comments in the complete script for the full details.

To create a box with custom borders, all you need to do is wrap whatever you want to be in it in a div element with a class name of cbb (use multiple classes if you like – the script is made to handle that):

  1. <div class="cbb">
  2. Box content
  3. </div>

This is the class you want to style for browsers with JavaScript turned off (or no support for the DOM methods used). View the JavaScript off example to see the very basic styling I applied.

And obviously you need to load the file containing the JavaScript:

  1. <script type="text/javascript" src="cb.js"></script>

The script adds the extra div elements and changes the class name from cbb to cb, so cb is the class used to attach the images. If you want to use other class names, just edit the initCB function in the JavaScript file.

And we're done

And there you have it, a resizable box with transparent custom corners and borders, no extra markup needed. To customise it, just replace the images with your own. If your custom borders have different dimensions than those used in the demo you will also need to adjust the CSS to account for that.

Got any suggestions for further improvement? Let's hear 'em.

Update: I've made some changes to fix a few of the glitches mentioned in the comments.

Problems fixed include:

  • Floating: You can now float the box without breaking it.
  • Margins: It is now easier to control the vertical margins of the box. This is especially notable when you have several boxes stacked on top of one another.

To fix this I changed the script a bit. It now inserts one more div element that wraps the box content. Doing that allowed me to ditch some of the relative positioning and negative margins, which were causing problems in some cases. I had to give one of the divs a 1px height to make IE happy, but that's something I'm getting pretty used to doing.

Customising instructions: For details on how to make your own graphics, check out Customising custom corners and borders.

This technique has been updated! Check out Transparent custom corners and borders, version 2 for a more recent version that fixes some problems in the version described here.

Posted on May 16, 2005 in JavaScript, CSS