Sunday, September 14, 2008

html and css: elegant rounded corners

Creating rounded corners for your DIVs and other HTML block elements isn't too tricky to figure out. However, some solutions are more elegant than others. And since I basically stole the following idea from Google, I'm going to claim it is a very elegant solution.

The concept is relatively simple. Any block element that needs rounded corners needs an image of each corner in each corner. One of the most elegant and most bandwidth saving solutions is to use the same image, a circle, for each corner and simply show the appropriate quadrant of the circle for the appropriate corner.

It's important to take notice of the nature in which we will be showing these images (one quadrant at a time) before we start adding them. While we may be able to come up with some CSS to do this to a normal image tag, it's sort of a moot technique. Rather, we can easily add a block type element, size it to 1/2 of the circle image dimensions, which yeilds 1/4 of the image, and set the image as a positioned background. Thus, this block element will act as a cropping tool for our image.

So, before we look at the CSS, let's take a look at the elements that need styling for this to work:
<div id="container">
<div class='corner top_left'></div>
<div class='corner top_right'></div>
<div class='corner bottom_left'></div>
<div class='corner bottom_right'></div>
</div>

I added the class names ahead of time because I know the images will need some special styling. And here it is:

div.corner {
position: absolute;
width: 8px;
height: 8px;
border: 0px;
margin: 0px;
padding: 0px;
background-attachment: scroll;
background-image: url(circle.png);
}

div.top_left {
top: -1px;
left: -1px;
background-position: 0px 0px;
}

div.top_right {
top: -1px;
right: -1px;
background-position: 8px 0px;
}

div.bottom_left {
bottom: -1px;
left: -1px;
background-position: 0px 8px;
}

div.bottom_right {
bottom: -1px;
right: -1px;
background-position: 8px 8px;
}

#container {
position: relative;
}

In this example, if it isn't obvious, circle.png is a 16x16 circle image. Each corner DIV is positioned to overlap it's assigned corner by a single pixel--to hide the border. And the container DIV is set to relative positioning so that the corner DIVs may be positioned absolutely. This should also work if the container DIV is positioned absolutely.

On the site that this particular example came from there is also another little optimization: circle.png is actually a script-generated image. The script takes in a radius, border width, background color, foreground color, and border color. From this, it generates a resampled (pseudo-anti-aliased) image and sends it with 1-year expires/cache-control headers.

So, if I change a background color or decide I want a more rounded corner, I can change the URL of the background image without having to manually create that image. And, as an added bonus, because I am using good image-expiration policy, each client should ask for the image only once.

I'm think most of this is pretty self-explanatory. But, feel free to ask questions if something is unclear. And if you want to generate some circles, you can play with my script a little: http://svidgen.com/circle.php. The parameters (via querystring, obviously) are as follows:

r: radius of the cirlce in pixels, capped at 128
bg: background color, use a stanard HTML hex value like aabbcc
b: border color, use a stanard HTML hex value like aabbcc
fg: foreground color, use a stanard HTML hex value like aabbcc
w: border width in pixels, capped
a: "anti-aliasing" level, capped at 4: the initial image is generated a times too large and resampled down.

So, you might do something like this: http://svidgen.com/circle.php?bg=ffffff&fg=f0faff&b=808080&w=1&a=4&r=8, which is used for http://thepointless.com. Though it's taken from a different server for thepointless.com.

Another thing to note: if you use my script to generate your rounded corners, I ask that you store the generated image on your server, since I'll soon be enabling some form of hot-link protection on the script. And if you use this technique or my circle script, it would be dandy if you could link to this article or one of my other sites to show your appreciation. Though, I won't get upset if you don't--it would just be dandy, you know?

Good luck!

P.S.
I'll probably publish the code for the circle-generator either in this blog or on svidgen.com in the near future.

1 comment: