Title Image

Don Xml's Grok This

The home of Don Demsak
Welcome to Don Xml's Grok This Sign in | Help
in Search

This Blog

Syndication

Site Sponsors

DonXml's All Things Techie

CSS Tutorial – Designing Without Tables and Not Lose Resizable, Custom Borders

One of my first blog posts (way back in April 2003 and on the old DotNet Weblogs site, now Weblogs @ ASP.Net) was called Pet Peeve – Using HTML Tables to Control Web Page Layout.  Since that early post I really haven’t seen much headway made in the .Net camp to oust the Table camp and replace them with the CSS Camp.  There are some things that are still pretty hard to do using pure Divs and CSS, which hinders the designing without tables movement (that and all major HTML Editor pretty much force Table layout down your throat).  Sure, VS 2005 is a big improvement for the CSS camp, and Microsoft New Web Designer (code named Quartz) looks to be heading in the right direction, but until we create better tutorials on how to use CSS instead of Tables, most folks will not use CSS for layout.

The one thing that I always dropped back into table layout mode was when I wanted to create custom borders that could automatically resize.  That was until just recently.  Over the long holiday weekend I took the time to sit down and try to come up with a pure Div and CSS template that I could use everywhere, on any browser, and with no javascript (like CSS layouts are supposed to be).  The site 456 Berea St. has a good article on Custom borders with advanced CSS, but it uses features currently implemented only in Safari.  For a cross-browser approach, Søren Madsen’s CSS Design: Creating Custom Corners & Borders was the approach that most CSS’ers used, since it had a more “semantically logical” feel to the markup.  The problem I always had with Søren’s approach has to do with graphics he uses.  They have an inherent scale limit, since he is clipping the image instead of repeating the border images in the x or y direction.  But, he has to do that to keep with the semantically logical markup.  In an environment that has both vector and layout markup languages in the rendering engine, Søren’s approach would be great (can you say Windows Presentation Framework?), but I wanted something that a Table layout person could easily wrap their head around without resorting to using tables (Mozilla has a implementation that just replaces the Table, TR, and TD elements with Divs, and makes use of special CSS pseudo table classes, but that markup is god awful.  If you must see it yourself, here’s a link to an example on my site, but remember it only renders correctly in Mozilla).

So, what I did is break down how I would normally use tables to create scaling custom borders, and then build it back up using XHTML and CSS.  I hit a bunch of gotchas along the way, but I think I finally came up with something the meets my personal requirements of not using tables, that worked on all modern browsers, but also living within the boundaries of XHTML and CSS.

When you create a graphic in something like Adobe Illustrator or Photoshop, to get a border to scale, you usually slice up the graphic and place the parts in what I call the 9 Box Layout:

Using table layout, you would create a table with 3 rows and 3 columns, with each cell mapping to its counterpart in the 9 Box layout (Table Layout Example).  Boxes 1,3,7,9 would not be repeating images.  Box 5 would have no image, only a solid background color.  Boxes 2 and 8 would normally be a small slice of that part of the image (only a couple pixels wide), and would repeat in the x direction.  Boxes 4 & 6, would be similar to 2 & 8, except that the image would only be a couple pixels in height, and repeated in the y direction.  Its simplicity is the reason why the Table layout for custom borders is so popular.  Once you have this done, all you need to do is set the width of the table, and the horizontal border scale without any other changes.  To adjust the height, just add you content to Box 5, and the height scales to the size of the content.

Now, I want to do the same exact thing, but with Divs and CSS, without using CSS pseudo classes that are not supported in all browsers and still have markup that isn’t a total mess.  Remember, if you want to force IE 6 into standards- compliant mode, you need to use the !DOCTYPE “switch” and put the proper DTD at the top of the document.  Otherwise IE renders differently than what is expected.  We will start with div to set the container for the “table”, set the width, and place in it what will be the Div for top row (Boxes 1,2,3).

<div id="Panel" class="TableLikeContainer" style="width:200px;">
    <div id="Box2">
    </div>   
</div>

CSS:
body {
    background-color:#CCCCFF
}

.TableLikeContainer {
    padding:0;
    margin:0;
}

Since we are using CSS for layout we can use the CSS Float attribute to float Box 1 to the left corner and Box 3 into the right corner.  We then set the background image for Box 2 to the same one in the Table Layout version and repeat that in the x direction.  Now we have Box 2 with the corners (Boxes 1 & 3) floating over the top of the row’s background image, which gives us scaling in the x direction.  If you want to have some text in the header, you can put that after the floating corner divs.

    <div id="Box2" class="CustomBorderTopBorder">
        <div id="Box1" class="CustomBorderTopLeftBorder">&nbsp;</div>
        <div id="Box3" class="CustomBorderTopRightBorder">&nbsp;</div>       
        <!--<h2>top</h2>-->
    </div>

CSS:
.CustomBorderTopBorder {
    height:30px;
    background: url(images/TopCenterBorder.jpg) repeat-x;
}

.CustomBorderTopBorder h2 {
    font-size:medium;
    text-align:center;
    padding-top:10px;
    margin-top:0;
    margin-bottom:0;   
}

.CustomBorderTopLeftBorder {
    width:30px;
    height:30px;
    float:left;
    background: url(images/TopLeftBorder.jpg) no-repeat;
}

.CustomBorderTopRightBorder {
    width:30px;
    height:30px;
    float:right;
    background: url(images/TopRightBorder.jpg) no-repeat;
}

What I found is that Mozilla doesn’t like to render the background images in Boxes 1 & 3 when they are empty, so I had to place non-breaking spaces in them to get Mozilla to render them.  You can repeat this for the bottom row, just swapping out the top images to the equivalent bottom ones.

So, I got the top and bottom done pretty easily using the CSS float attribute.  You may think that you could do the same thing with the middle row, but due to the nature of floating, they do not automatically scale to the height of the container (which makes sense for floating, but it isn’t what we want here).  So, I had to get a little more complicated then I would have liked, and had to nest the Divs, so that Box 4 contains Box 6, which then contains Box 5.  Sort of funky smelling, but it works.

    <div id="Box4" class="CustomBorderLeftBorder">
        <div id="Box6" class="CustomBorderRightBorder">
            <div id="Box5" class="CustomBorderCenterContent">
            </div>
        </div>
    </div>   

CSS:
.CustomBorderLeftBorder {
    height:100%;
    background: url(images/MiddleLeftBorder.jpg) repeat-y;
}

.CustomBorderRightBorder {
    background: url(images/MiddleRightBorder.jpg) repeat-y 100% 0;
}

.CustomBorderCenterContent {
    margin-left:30px;
    margin-right:30px;
    background-color:white;
}

The trick here is to nest them, so that the outer boxes (4 & 6) have to scale with the content, and repeat the image along either side along the y axis.  Another trick is to set the left and right margin of Box 5 to the width of the border graphic, which will make sure your content is indented on the left side, and leave the proper amount of space on the right, so you can just set the position of the repeating right border to 100% (since the width of the border is not part of the overall width of Box 5, see the definition of the Box model if you want the gory details of why this works and is actually correct).  Using the Box model to our advantage helps us not have to hard code the width of the “table” anywhere in the markup or the CSS.  The width is set by the CSS width attribute on the “table” Div (which I labeled Panel).  Now, any content you have can be placed within the Box 5, and everything will scale.

Well, that last statement isn’t 100% correct.  Everything almost always scales in all browsers.  Turns out that the feature we used to our advantage in laying out the right border for Box 6, aka the Box Model, comes back and bites us, but only for non IE 6 browsers.  If you only use Divs within Box 5, everything looks great in Mozilla, but who uses all Divs?  If you use P, Hn, or OL elements, they will automatically set the top and bottom margins (which will give a paragraph some space between it and other markup).  Remember I said that in the Box Model Margins are not used to calculate the width of the element, well the same is true for the height.  So the height of the nested boxes (4,5,6) does not match the distance from the Top and Bottom Rows which creates some extra space between the middle row and the other rows.  But, for some reason, although IE is supposed to be in standards-compliant mode, it still uses the wrong height and width calculation for of the background size and location.  It may look “right”, but I tend to trust Mozilla’s implementation of the Box Model over IE (but I haven’t verified which one is actually correct).  The solution is pretty easy, just set the border-top and border-bottom to 0, and instead use padding-top and padding-bottom (which, according to the Box model is included in the height and width calculation).

            <div id="Box5" class="CustomBorderCenterContent">
                <!-- margins don't count in the height -->
                <p>asdfadsf</p>
                <p>asdfadsf</p>             
            </div>

CSS:

.CustomBorderCenterContent p {
    margin:0;
    padding-top:0.25em;
    padding-bottom:0.25em;
}

The Box Model will also mess with the content in both the top and bottom rows, so you have to remember to do a similar thing there too.

.CustomBorderTopBorder h2 {
    font-size:medium;
    text-align:center;
    padding-top:10px;
    margin-top:0;
    margin-bottom:0;   
}

Hopefully, this is something that the Table Layout crowd can use to wean themselves off of tables and over to CSS driven layouts.  One of these days I’m actually going to migrate this site off of the old .Text blog engine and onto CommunityServer 2.0, and while reskinning the entire site, use these templates.  Although Scott seems to have drunk the CSS cool-aid, there are still lots of tables used for layout in the default skins.

If you want to download these examples and play with them yourself, I zip them up for you (and even included the Illustrator file I used to create the custom borders).

Published Wednesday, December 28, 2005 8:47 PM by donxml

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

Toby Henderson said:

Thanks for doing that, I've been promising to do the same thing for ages. Nice and easy to read and follow.

I also found this a while back to help out with Css tables:
http://www.positioniseverything.net/articles/pie-maker/pagemaker_form.php

Helps getting you going quickly.

Toby
December 29, 2005 9:13 AM

Chris Wallace said:

I guess my first comment failed to go through and of course I can't remember what I said. Anyway, there are some caveats with this layout. What if you want the borders to cover your entire content area? Setting the width of the container to 100% works as expected and the area fills to cover the browser window as expected. Unfortunately, height isn't so simple. You can set the height to a percentage in a couple of places (I forgot which ones now) that will cover you in IE but other browsers don't work the same as IE (as we all know) and setting height to a percentage is pretty much useless. I'm sure there is a workaround for this; I just didn't have time to explore further.
December 29, 2005 10:43 AM

Don Demsak said:

Chris, Yes this will not work if you tried to scale to 100% height, like you can do with Tables. Except for the fact that the Height Attribute is not legit on a Table element, according to the HTML 4.01 Strict spec. Yes, browsers do support it, because the old Netscape browser supported it, but if you write valid HTML or XHTML, you couldn't use the Height Attribute on a Table. Since I'm trying to stick to standards here, this solution works according to the Table spec.

Oh, sorry about the comment bug. It's a known bug with the Captcha stuff I'm using. The Captcha control uses session to cache the value, and if you spend too much time on the page, session will be lost. It shouldn't be a problem once I switch to CS 2.0.
December 29, 2005 3:10 PM

Chris Wallace said:

Well, you can do 100% height by using an image background in combination with the correct cascade of styles, I just didn't have enough time to work it out for your layout this morning. It's a common problem with 2-column css designs because unless you design the layout properly one column will often appear to be longer due to it's content (it actually is and should be longer but you usually want it to be appear to be the same length). I had to work around this with the design on my site (except my blog, I still have to fix it to be compliant).
December 29, 2005 4:04 PM

Glenn said:

very informative dude, am planning to redesign my site without table, thru the help of your css samples.. God bless
May 20, 2006 6:22 AM

Brian said:

I ask this not to be a wise guy, but as somewhat of a newbie to all of this. Isn't this a lot of trouble to go to just to avoid using a table?
August 16, 2006 10:23 AM

Don Demsak said:

Brian,
I know it might seem to be a waste of time to a newbie, but eventually you realize that mixing layout into your HTML just makes life harder, not easier. But, that being said, this example does still mix layout into your HTML, even though it doesn't use Tables. The problem is really with the current status of XHTML. We are stuck with all this legacy HTML, and no one really cares about generating valid XHTML & CSS. But if you do want to see how it is suppose to work, check out www.csszengarden.com. What you get there is the perfect example of separating Layout from HTML, enabling the Graphic Artist to give the same XHTML document many different looks, without having to change the underlying XHTML.
August 16, 2006 10:59 AM

Leave a Comment

(required) 
(optional)
(required) 
Submit

About donxml

I’m an independent consultant, specializing in .Net solutions architecture, based out of New Jersey who also doubles as an evangelist for XML, Domain Driven Design, enterprise architecture and .Net. I do not work for Microsoft, the W3C or any other big company that you may know of (at least not yet). I’ve been an indie for over ten years, and although I’ve been tempted a couple times to take a job with companies like Microsoft, I’ve haven’t found something better than my current situation. I work mostly with the large pharmaceuticals that are based here in New Jersey, and usually find myself on long term contracts. Definitely not the prototypical indie consultant, but it lets me dedicate time to my non-income generating activities like the developer community stuff, plus financing open source projects like XPathmania and MVP-XML. If you would like to talk to me about doing some contract work, just contact me via the contact page. My rates vary widely, depending on lots of different variables, but mostly distance from Jersey, and type of work. Plus, I’ve been known to donate some of my code for various projects.
Powered by Community Server, by Telligent Systems