With all the guides on how to create those wonderfully popular web 2.0-ish rounded corner boxes out there it is easy to say it's a crowded space. Although there are tons of guides out there utilizing all manner of technology, from pure-css to javascript solutions, I had a very specific requirement that wasn't satistfied by any of them (that I know of): a method of creating resizable boxes with custom designed rounded-corners that could be overlayed on a patterned background.
That is a mouth full, but all the solutions I found out there either only worked on a solid background color or had limited customizability in terms of the corners themselves (often a side-effect of the JS solutions). You see, a sensible developer would have told the client that their graphic designer's mockup needed to be changed to make the site more html/css friendly, but I am by no means a sensible developer - trust me. No, I am the consummate customer servicer. There is no 'no', even when there should be.
So how can we accomplish this very specific feat? With a solution that is neither slim nor elagant. All four corners need to be independetly defined and styled. Both the top and bottom edges need to be fixed width. What we end up with is a hefty bit of html and css, but it gets the job done. You can see below doms have been defined:
As you can see, there are both top and bottom divs that contain each set of corners. The blue box is our content space. This particular example is an extreme case of course, given the large drop shadow and large radius of the corners.
There is one big reason why the traditional methods of creating rounded corners fall short when layed over a patterned background: the pattern will not match up for a floated or resizable div. Because you are using images with transparencies you have to set the background of all slices except the content area to be transparent. But because we need all these transparencies, the main content area has to be walled off otherwise its background color will bleed into the surrounding divs.
The result is a solution that is heavy-handed but gets the job done. Because of the nature of this layout, creating liquid elements is not possible. Instead, the width must be defined and remain static. ; So are you ready for the code? I know you are, so here it is:
First, the HTML:
<div class='rbox_container' id='rbox'>
<div id='rbox_holder'>
<div id='rbox_topleft'></div>
<div class='rbox_top_connector' id='rbox_middle'></div>
<div id='rbox_topright'></div>
</div>
<div id='rbox_content' >
<div id='mainbox'>
<div class="content">
Your Content Goes Here
</div></div></div>
<div id='rbox_holder'>
<div id='rbox_bottomleft'></div>
<div class='rbox_bottom_connector' id='rbox_middle' ></div>
<div id='rbox_bottomright'></div>
</div>
</div>
See what I mean? Here's the synopsis: We have inside the rbox (rounded-corner-box) three main sections - the top and bottom rbox_holder divs and the main body. These rbox_holders hold the corners and divs that connect those corners on the top and bottom edges. So you will see above the rbox_topleft, rbox_top_connector and rbox_topright elements all sit inside the top rbox_holder, gently resting against each other as they float to the left.
You then will see three boxes dedicated to the main content area: rbox_content, mainbox, and content. The rbox_content div contains the right_edge.png y-repeated image. We want a solid color for the body of our rounded-corner box, but we can't set rbox_content's background color to anything other than transparent or it will spill into our transparent image. This is where the mainbox div saves the day by picking up the slack and making the body of our beautiful rounded-corner box a solid color. In fact mainbox is saving every other element from having to specifiy a background color, so it really is the pillar of this arrangement.
The bottom rbox_holder plays out in the same way the top does and it's all wrapped up nicely by the rbox_container div, which can then be floated or positioned in any way you wish.
The Images:
These images comprise the makeup of the rounded corner boxes. This of course assumes you want a drop shadow this dramatic. You can use any styling you want, and as long as your slices are as big or bigger than the ones you see here, you can make them work by nudging them around in the css above.
Here are the PNGs for non-retarded browsers
![]()
Here are the GIFs for browsers with special needs
![]()
* Note: these images have transparent backgrounds *
So what does the CSS look like for this puppy?
The CSS:
div#rbox{height:auto;margin:20px;float:left;}
div#rbox_holder,div#rbox_topleft, div#rbox_bottomleft, div#rbox_topright,
div#rbox_bottomright,div#rbox_middle,div#rbox_middle_news, div#rbox_middle_full {height:66px;}
div#rbox_holder { width:100%;}
div#rbox_topleft, div#rbox_bottomleft {float:left;width:60px;}
div#rbox_topleft { background:url('top_left_corner.gif') no-repeat 6px -6px;} /* IE6 */
html>body div#rbox_topleft { background:url('top_left_corner.png') no-repeat 6px -6px;}
div#rbox_bottomleft {width:60px; background:url(bottom_left_corner.gif) 0px -12px no-repeat;} /* IE6 */
html>body div#rbox_bottomleft {width:60px; background:url(bottom_left_corner.png) 0px -12px no-repeat;}
div#rbox_topright, div#rbox_bottomright {float:right;width:60px;}
div#rbox_topright {background:url(top_right_corner.gif) no-repeat -14px -2px;} /* IE6 */
html>body div#rbox_topright {background:url(top_right_corner.png) no-repeat -14px -2px;}
div#rbox_bottomright {background:url(bottom_right_corner.gif) -14px -12px no-repeat;} /* IE6 */
html>body div#rbox_bottomright {background:url(bottom_right_corner.png) -14px -12px no-repeat;}
div#rbox_middle {float:left;}
div#rbox div#mainbox {background:#fff;width:648px;margin-left:-11px;padding-left:10px;}
div#rbox div#mainbox div.content {position:relative;top:-50px;}
div#rbox div#mainbox div.content p {margin:0px;}
div#rbox_content {padding:0 20px 0 20px; background:transparent url('right_edge.gif') repeat-y; 665px 0px;} /* IE6 */
html>body div#rbox_content {padding:0 20px 0 20px; background:transparent url('right_edge.png') repeat-y 665px 0px;}
.rbox_container {width:700px;}
.rbox_top_connector, .rbox_mainbox2_bottom {width:580px; background-color:#fff; }
.rbox_bottom_connector {width:580px; background-color:none; background: url('bottom_edge.gif') repeat-x 0px -12px;} /* IE6 */
html>body .rbox_bottom_connector {width:580px;
background-color:none; background: url('bottom_edge.png') repeat-x 0px
-12px;}
BLAHHH! It's like my text editor just puked all over the page! Bare with me. The important parts to pay attention to are the big widths highlighted in yellow and green. These are what define the overall width of your whole box, and they all worship one master - the green highlighted rbox_container width, which is the actual width of the whole shebang. If you change this value, you must change every yellow value by the same amount. Sounds a bit tedious, doesn't it? Well if you're a rails developer, you're in luck: I will provide you with a way to clean this whole mess up and easily manufacture these beauties with a nice DRY approach.
Because this rounded corner method isn't the prettiest I wanted something dead simple to use in my views, but I also needed something that made it easy to resize these boxes without having to repeat the calculation for every different width. I wanted it to look something like this:
<% rbox(400) do %>
stuff inside the box
<% end %>
That's a hell of a lot prettier than the HTML above, isn't it? Here's how it's done:
First we need to add a few methods to our application_helper.rb file. The first one takes any block of html we have in our view and packages it up to be sent to our partial.
def block_to_partial(partial_name, options = {}, &block)
options.merge!(:body => capture(&block))
concat(render(:partial => partial_name, :locals => options), block.binding)
end
The second method we need is the actual rbox method which takes a width in pixels. The options parameter could take a class name too if you wanted to uniquely define rboxs for manipulation in your css.
def rbox (width, options = {}, &block)
block_to_partial('examples/rbox', options.merge(:width => width), &block)
end
The partial of course contains all our rbox html from above.
<% extension = "png" %>
<% extension = "gif" if ie? %>
<div class='rbox_container' id='rbox' style='width:<%=width%>px;'>
<div id='rbox_holder'>
<div id='rbox_topleft'></div>
<div class='rbox_top_connector' id='rbox_middle' style='width:<%=width-120%>px'></div>
<div id='rbox_topright'></div></div>
<div id='rbox_content' style='background:transparent url(/images/examples/right_edge.<%= extension %>) repeat-y <%=width-35%>px 0px;'>
<div id='mainbox' style='width:<%=width-52%>px'>
<div class="content">
<%= body %>
</div></div></div>
<div id='rbox_holder'>
<div id='rbox_bottomleft'></div>
<div class='rbox_bottom_connector' id='rbox_middle' style='width:<%=width-120%>px'></div>
<div id='rbox_bottomright'></div></div></div>
The bit of extension code above determines whether the browser in use is ie6 or not and uses the appropriate gif if that is the case. It takes advantage of our last helper method:
def ie?
m = /MSIE\s+([0-9, \.]+)/.match(request.user_agent)
unless m.nil?
m[1].to_f
end
end
So that should do it. Let's look at the final result one last time:
<% rbox(400) do %>
stuff inside the box
<% end %>
MMMmmmm MMM, lookin good. So now it's time to see this thing in action.
If you have any questions or suggestions for improvement, and even if you have or know of a better solution, please post them in the comments section.










Stephen Orr on Tuesday, June 24, 2008 at 05:22AM
I'm not entirely sure in this case why you couldn't simply use transparent PNGs (yes, I know they don't work in IE6 - but there's ways to solve that) - as long as the PNGs don't include your background pattern, it won't matter where they're overlaid on the pattern because there's no chance they won't match up.
That said, this is an effective solution - not necessarily the easiest, but it works.
As far as IE6 compatibility goes, I usually use transparent PNGs for everything that supports them, then using conditional comments either override those with transparent GIFs for IE6 (as you've done) or include the previously mentioned PNG Fix javascript to solve that issue.
Mark Nutter on Tuesday, June 24, 2008 at 07:32AM
I am using transparent PNGs, but using them introduces an interesting problem - the body of the box needs to be defined independently of the corners since it has a background color and the corners can't have one.
Also, I am checking for IE6 in the Rails code above, which replaces the PNGs with GIFs as necessary.
on Thursday, August 07, 2008 at 08:21PM
on Thursday, August 14, 2008 at 05:46AM