Loved by designers and loathed by developers, rounded corners can be a real pain if you don’t plan ahead or aren’t aware of the problems.
Skip to it!
The problemTM
There are myriad ways to approach the problem. CSS 3 has them built in or you can do it all with markup and CSS, I think there’s also a built in jQuery approach to it as well as a large number of javascript only solutions. My personal take on the problem is taken from years of wrestling with the issue and I like to stick with what I know if I’m already happy it works and is a sensible solution rather than learn what someone else has put together. You know what you know, you know?
I personally hate extra markup to accommodate design conceits such as rounded corners as I’ve seen it tackled clumsily before. The following is based on code from the furniture of a live site which I won’t name.
It was provided by a freelance agency and not done by the very competent team I know who work for the owners of the site.
Sadly this is part of the problem of hiring external resources for your work when your core team is pressed for time and you have no one competent to sanity check the work.
That’s another issue entirely and not one that’s within the scope of a single freelancers site. On to the code…
The HTML
<div id="some_id"> <div class="tl"> <div class="tr"> <div class="br"> <div class="bl"> <p>Content</p> </div> </div> </div> </div> </div>
The CSS
#some_id {
display:block;
position:relative;
background: url(images/backgroundimage.png);
}
#some_id tl,
#some_id tr,
#some_id bl,
#some_id br {
display: block;
position: relative;
background-repeat: no-repeat;
}
#some_id tl {
background: url(images/tl.png);
background-position: top left;
}
#some_id tr {
background: url(images/tr.png);
background-position: top right;
}
#some_id bl {
background: url(images/bl.png);
background-position: top left;
}
#some_id br {
background: url(images/br.png);
background-position: bottom right;
}
This to me seems heavy. It also appears on every element with rounded corners on the page, this case the homepage, a whopping eleven times! That’s forty four extraneous elements on the homepage alone!
I would have approached it in the past by doing the following. It also has separate images for each corner which is a small but added strain on the server as the sum of the individual parts is greater than a single whole due to file headers. This snowballs quickly if it’s a high traffic site.
My old solution
<div id="some_id"> <span></span> <span></span> <span></span> <span></span> <p>Content</p> </div>
As you can see, although there’s less nested nonsense it still adds a fair amount of markup. Incidentally I use spans because they’re semantically meaningless unlike divs. You can read more about them here: Wiki entry on spans and divs.
Hopefully you will have noticed that they’re not nested either. One of the reasons that I like them in a context like this is that if for any reason the CSS fails out then spans naturally have no layout so they’ll collapse without any breaking of your overall styles.
My old CSS
#some_id {
position: relative;
min-height: 20px;
}
#some_id span {
background: url(images/corners.png) 0 0 no-repeat transparent;
position: absolute;
display: block;
width: 10px;
height: 10px;
top: 0;
right: auto;
bottom: auto;
left: 0;
}
#some_id span+span {
background-position: -10px 0;
top: 0;
right: 0;
bottom: auto;
left: auto;
}
#some_id span+span+span {
background-position: 0 -10px;
top: auto;
right: auto;
bottom: 0;
left: 0;
}
#some_id span+span+span+span {
background-position: -10px -10px;
top: auto;
right: 0;
bottom: 0;
left: auto;
}
I really like this solution, it’s clean, doesn’t have any extraneous non-semantic class names littering up my lovely descriptive markup and doesn’t suffer too badly from divitis.
Sadly this approach won’t work in all browsers though as it relies heavily on sibling selectors so although it’s better it’s still not 100% there. There’s also the issue that it’s still introducing a great deal of code in the page for a fairly useless design frippery (don’t kill me pixelpushers, I mean no offense).
This is a good starting point but the amount of repeated code makes me feel like there’s a better way of approaching it.
My new solution
This is where we introduce some very very simple jQuery. The reason it’s so simple is that I’m not very good at it and I need to keep things simple or I get confused.
There are enough common elements to the markup I use to make a function out of it.
My new HTML
<div id="some_id" class="corners">
<p>Content</p>
</div>
That’s it, the only addition we need is the “corners” class.
My new CSS
#some_id {
position: relative;
min-height: 20px;
}
#some_id span {
position: absolute;
display: block;
}
#some_id .tl {
background-position: 0 0;
top: 0;
left: 0;
}
#some_id .tr {
background-position: -10px 0;
top: 0;
right: 0;
}
#some_id .bl {
background-position: 0 -10px;
bottom: 0;
left: 0;
}
#some_id .br {
background-position: -10px -10px;
bottom: 0;
right: 0;
}
What’s that; I’ve gone backwards a step by adding classes to the spans? Well yes and no, we’re making concessions for browsers that don’t understand what to do with sibling selectors hence the class names but because we’re adding the spans via client side scripting we’re not bloating the page, diluting our semantic markup or increasing the load from the server with extra calls. The next bit is the cool bit.
The jQuery
$(document).ready(function() {
$('.corners').each(function(){
$(this).append('<span class="tl"></span><span class="tr"></span><span class="br"></span><span class="bl"></span>');
});
});
Before this will work you’ll need to include the jQuery library from the jQuery website or do what I do and just link directly to the latest version.
I’ve currently got my specific corner styles in a separate stylesheet called corners.css and suggest you do the same so you can do things like alter the size, background image and position.
Now all that’s left to do is add a class of corners to each element you want to have affected. You can use a set of single images and move about about with CSS as I do currently or you can put all of your images on a spritesheet as I will later. But that’s a story for another night.
So that’s it. I hope I’ve not left anything important out or any glaring errors in the markup or CSS but if there are then please send me a message at pete@republicofpete.net or just leave a message in the comments.
#1 by jon bennett on March 6, 2010 - 10:11 am
Quote
Hi Pete,
It’s a shame one can’t use content attribute to inject the html, wouldn’t need js at all then.
Working examples of each technique would be good.
J
#2 by Flowdeeps on March 6, 2010 - 10:26 am
Quote
Yeah, I thought about it briefly but it’s not really what CSS if for is it. Imagine the havoc you could cause if yu could insert HTML and JS and what-not willy-nilly with just some CSS.
Best leave it to 5 lines of pseudo JS.
I’ll think about doing a demo page.