Rounded corners with CSS and JavaScript

Quite a few people have tackled the issue of rounded corners in CSS already. However, all these techniques suffer from the same problem: non-semantic markup.

The Issue

By “non-semantic markup,” I’m referring to markup which has no semantic purpose on the page - markup which exists solely for presentation reasons.

We want to avoid this. Markup should exist to convey information to the user, not presentation and style. Non-semantic markup bloats the page and makes it more difficult for some browsers (such as text browsers or screen readers for the blind) to render the page correctly or efficiently.

The Solution

The solution comes in the form of low-impact scripting. This is a term I’ve coined to describe the philosophy I use when implementing JavaScript. In a nutshell, low-impact scripting is a collection of techniques which minimize the number of changes needed to implement a feature by leveraging the DOM and CSS from JavaScript.

This will become more clear as we move on.

The Approach: HTML & CSS

We’ll use a pretty standard technique here - the “magic sauce” here will be the scripting we add later.

The markup:

<div class='roundbox'>
    <h3>Rounded corners</h3>
    <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean gravida. Pellentesque nonummy nunc eu ante.</p>
    <div class='corner ul' / > <div class='corner ur' / > <div class='corner bl' / > <div class='corner br' / >
</div>

The style:

.roundbox { position: relative; border: 1px solid black; }

.roundbox .corner { position: absolute; height: 16px; width: 16px; overflow: hidden; }

.roundbox .corner.ul { top: -1px; left: -1px; background: url('corner-ul.png') no-repeat; }
.roundbox .corner.ur { top: -1px; right: -1px; background: url('corner-ur.png') no-repeat;}
.roundbox .corner.ll { bottom: -1px; left: -1px; background: url('corner-ll.png') no-repeat; }
.roundbox .corner.lr { bottom: -1px; right: -1px; background: url('corner-lr.png') no-repeat; }

This should be pretty clear. The only thing of note here is this: overflow: hidden;. While testing this in IE, it was ignoring the height property on the corners, and giving the corner divs the same height as a line of text. This forces it to keep them at 16×16.

The Problem

The problem with this technique is the markup required to pull it off. It’s ugly and non-semantic. And if you want to generate rounded-corner boxes from PHP (or a CGI, or whatever), you’ll have to stick all that markup somewhere in your code. Ugly.

The Solution: JavaScript

The solution is to drop the non-semantic markup, and recreate it with JavaScript.

The code:

/**
 * RoundBox support
 *
 * @copyright   (c) 2005 WebSprockets, LLC
 * @author      Ian Eure
 * @license     LGPL
 */

/**
 * Initialize a RoundBox
 *
 * @param   HTMLElement  box RoundBox element to initialize
 * @return  void
 */
function initBox(box)
{
    var tl = document.createElement('div');
    tl.className = 'corner tl';
    var tr = document.createElement('div');
    tr.className = 'corner tr';
    var bl = document.createElement('div');
    bl.className = 'corner bl';
    var br = document.createElement('div');
    br.className = 'corner br';

    box.appendChild(tl);
    box.appendChild(tr);
    box.appendChild(bl);
    box.appendChild(br);
}

/**
 * Initialize all boxes on a page
 *
 * This initializes any div with a class of 'roundbox'
 *
 * @return  void
 */
function initBoxes()
{
    var boxen = document.getElementsByTagName('div');
    for (var i = 0; i < boxen.length; i++) {
        if (boxen[i].className == 'roundbox') {
            initBox(boxen[i]);
        }
    }
}

initBoxes();

As you can see, this code searches through a document looking for divs with a class of ’roundbox.’ It then adds the corner divs to them. Including this effect on your page is as easy as dropping the code into roundbox.js and adding:

<script type='text/javascript' src='roundbox.js'></script>

To the bottom of your page. Browsers which don’t support scripting still get a border, but lack the rounded corners.

Mozilla issues

Mozilla seems to occasionally draw the corners in the wrong places, resulting in a 1 pixel horizontal and/or vertical alignment issue. Safari, Konqueror, and IE don’t seem to display this problem. I don’t know what causes it, but let me know if you find a solution.

You can see this effect in action on the WebSprockets site.

Leave a Reply