Post Archive
› October 17, 2005
Introducing DomCorners
DomCorners is a very simple technique for getting rounded corners, which has been presented on pro.html.it, the italian portal I write for, on the 31 of August 2005. When I developed it in July, I wanted to get a lightweight solution, simple to use and flexible. So I started thinking and came up with a solution that relies entirely on javascript and images, it's unobtrousive, has very good browser support and is very minimal.
And yes, it uses images. This may sound weird to the people who know about my work on Nifty Corners. While I simply love them, in developing DomCorners I nearly forgot about them and started with a very different approach, with simplicity as my main goal. The basic inspiration of DomCorners is Douglas Livingstone's four corners. It all started when I realized that a single image could be used to light up the technique. So here is the bare-bones HTML and CSS example of the technique. The markup looks like this:
<div id="box">
<b class="btop"><b></b></b>
content here...
<b class="bbot"><b></b></b>
</div>
Here's the CSS for rounded corners:
b.btop, b.btop b, b.bbot, b.bbot b{
display: block;height: 10px;font-size: 1px;
background-image:url(rc.png);
background-repeat: no-repeat}
b.btop b{background-position: 100% -10px}
b.bbot{background-position: 0 -20px}
b.bbot b{background-position: 100% -30px}
And finally the single image used wich combines the four corners, starting from the top left, then top right, bottom left and finally bottom right:
Next step obviously was to cut off extra markup and CSS. Have a look on the basic example which uses only javascript, mainly built with DOM. If you see the HTML code of the example, in the head section you'll notice these lines:
<script type="text/javascript" src="domCorners.js"></script>
<script type="text/javascript">
if(DomCheck()){
DomCorners("box","rc.png",10);
}
</script>
The first line embeds the small general javascript, while the others are for getting rounded corners on the specific page. I left them embedded for demonstration: obviously you could move these lines in an external javascript too, for example in domcorners.js.
The embedded script after a check for the DOM availability calls the DomCorners function to round the element. The function needs three parameters: the first one is the ID of the element to round, the second one is the image to be used and the third one is the height (in pixels) of a single rounded corner in it.
A few words about the script: I've provided a commented version, which is less than 30 lines. The DomCorners function performs a check a predefined intervals of 50ms to see the availability in the DOM of the element with a given ID. If it's ok, it simply inject the elements for rounded corners with the needed style declarations. After 200 tries (10 seconds) the function stop trying so you can call it even on a page where the given ID doesn't exist being sure it won't loop endlessy. A timer-based approach makes the script run faster than the onload and makes DomCorners a plug-and-run solution that won't give conflicts with other scripts.
Now let's see the second example, a two column liquid layout which uses DomCorners and just five images. The embedded script on the page is as follows:
if(DomCheck()){
DomCorners("header","head.png",10);
DomCorners("content","content.png",10);
DomCorners("menu","side1.png",10);
DomCorners("links","side2.png",10);
DomCorners("footer","footer.png",5);
}
Each call to the DomCorners function has the purpose of rounding an element, and as in the first example parameters are in order id, image to be used, and height in pixel of a single corner: notice that the footer has smaller corners than the other elements.
And finally the third example which uses just two gifs partially white and partially transparent. In this case you don't have to prepare an image that matches the background each time, since transparency will do everything: just be sure to use muted-tone backgrounds because GIFs are in fact aliased corners.
Even in this case, let's see the javascript calls:
if(DomCheck()){
DomCorners("header","transparent.gif",5);
DomCorners("content","transparent.gif",5);
DomCorners("menu","transparent.gif",5);
DomCorners("links","transparent.gif",5);
DomCorners("footer","small.gif",2);
}
That's it. Finally, a small note on compatibility: support of the script should be extended to browsers with a minimum of CSS and DOM capablities: the examples of this article have been tested on IE5, IE5.5 and IE6 and the latest versions of Opera, Firefox and Safari. Enjoy!
Comments
1. October 17, 2005 09:50 PM
2. October 17, 2005 11:05 PM
Nate Posted…
Hi Mike, the b tag code isn't really *in the markup* so to speak - it's inserted post-haste via the Javascript. If you look at the markup in the examples, it's clean. I think one could argue that even so, the inserted code should be valid, but I'm guessing that Alessandro chose this method because it's somewhat shorter.
3. October 18, 2005 07:47 AM
Tom Posted…
Nice article, I have hesitated using many of the rounded corner techniques due to bloatedness. This one is pretty clean. I like the use of the DOM to get the job done.
There does seem to be an issue in FireFox in your last example with the corners not fully being at the bottom of the box, so you get a wierd horizontal line. I've seen this behavior before in FF and it can be a real pain to solve. Here is a screenie:
I included a little blowup and arrows to show what I mean. I don't see that on the first example for some reason. Nice job. If that could be solved this would be pretty bulletproof.
Tom
4. October 18, 2005 11:08 AM
Craig Snyder Posted…
This is a very interesting technique but it seems to me that Nifty Corners has the advantage in every respect. I am also viewing the Firefox "misbehavior".
5. October 18, 2005 12:51 PM
Alessandro Fulciniti Posted…
Mike, the point it that an empty element couldn't have a semantical meaning so I used a presentational tag such as b (as I did in the html example of nifty corners) since it's short and it's inline, so it could be inserted in every kind of element. Obviously the <b> soup disappear in the js-powered version, but I think it was important to show the html+css version in order to let people understand better how the script works.
Tom, could only guess that the exceeding stripe it's due to the famous Gecko 1px rounding error... and I think the problem it's not in the script itself, but the page CSS.
Craig, obviously Nifty Corners are too far easy and versatile since no images at all are involved. DomCorners are just a little toy but might be useful when you want to get bigger corners, better antialiasing or simply a lighter solution.
6. October 18, 2005 02:41 PM
7. October 18, 2005 04:12 PM
8. October 20, 2005 04:33 AM
richard Posted…
Uh, is this what I think it is? This technique has been published in 2002 by FCZBKK, wasn't it?
9. October 20, 2005 07:21 AM
10. October 23, 2005 04:55 AM
Jacob Posted…
Tom, could only guess that the exceeding stripe it's due to the famous Gecko 1px rounding error... and I think the problem it's not in the script itself, but the page CSS.
The line is almost certainly by Gecko's 1px rounding error. The solution is to ensure that all sizes are whole pixel values and the bug disappears. This means all sizes - including margins, padding, borders, line height etc. Sometimes you can avoid problems whilst still having odd sizes but it gets complex.
By the way, the guys at Mozilla are working on a correction for this bug - it's filed on Bugzilla somewhere but I've lost the link I'm afraid.
Nice technique for making corners by the way - this is by far the cleanest solution I've seen.
11. November 13, 2005 07:25 AM
Posted…
I'm not sure I understand this .. but would it allow a border on the box?
12. November 15, 2005 05:26 AM
Matthew Posted…
I don't think this technique would allow nice borders, but is probably a bit more compact than the border technique I've been using on my current project. The link for that is below (I didn't write it, but the results are _really_ gorgeous given a nice input image - if you use it, thank Roger Johansson in the comments on that page!)
http://www.456bereastreet.com/archive/200505/transparent_custom_corners_and_borders/
13. December 23, 2005 07:10 PM
alexander Posted…
This was truly brilliant, I looked at niftycorners but its way too much code.. I would never add their 174 lines of code for something as simple as rounded corners, who cares if they support IE 0.3 using 200 workarounds. I want something that works in IE 6, ff, opera and safari, and what you got here seem to do just that! Very nice job!!
14. December 30, 2005 11:43 AM
sam Posted…
hi, is it possible to put vert.scrollbar in such curved box from top till bottom?
15. February 9, 2006 07:35 PM
sup Posted…
I find that I often wish to round only the top or only the bottom corners of a div. In addition, I prefer to apply this type of behavior based on an element's class rather than it's id. I modified DomCorners to support these needs. Here's the code I use:
// these vars are used as masks
var _ROUND_UPPER = 1
var _ROUND_LOWER = 2;
// cls: className; used to select the elements to round
// img: imageName; name of the corner image
// mask: 1, 2, or 3 (1 for top only, 2 for bottom only, 3 for all)
// size: size (in pixels) of a single corner in the corner image
function roundCorners(cls,img,mask,size){
if (mask == null) mask = 3;
if (size == null) size = 10;
var els = document.getElementsByClassName(cls);
for (var i = 0; i < els.length; i++) {
var el = els[i];
var c=new Array(4);
for(var j=0;j<4;j++){
c[j]=document.createElement("b");
c[j].style.display="block";
c[j].style.height=size+"px";
c[j].style.fontSize="1px";
c[j].style.border="none";
c[j].style.padding="0px";
c[j].style.margin="0px";
if(j%2==0)
c[j].style.background="url("+img+") no-repeat 0 -"+ j*size + "px";
else
c[j].style.background="url("+img+") no-repeat 100% -"+ j*size + "px";
}
if (mask & _ROUND_UPPER) {
c[0].appendChild(c[1]);
el.insertBefore(c[0], el.firstChild);
}
if (mask & _ROUND_LOWER) {
c[2].appendChild(c[3]);
el.appendChild(c[2]);
}
el.style.padding="0";
el.style.border="none";
}
}
I call it like this:
// round all four corners of elements whose className is myClass
roundCorners("myClass", "myCornerImage.gif");
// round top corners of elements whose className is myOtherClass
roundCorners("myOtherClass", "myCornerImage.gif", _ROUND_UPPER);
the function document.getElementsByClassName is from Prototye and looks like this:
document.getElementsByClassName = function(className, parentElement) {
var children = ($(parentElement) || document.body).getElementsByTagName('*');
return $A(children).inject([], function(elements, child) {
if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
elements.push(child);
return elements;
});
}
Mike Rundle Posted…
This technique sounds pretty cool, but I have to ask, what's up with the HTML? It's possibly the worst code I've seen ever posted on web-graphics. B tags instead of strong, no text inside of them, what gives?