How to make a box correctly

The way boxes are currently constructed on Battrick, gives rise to a serious case of "divitis". This page looks at how it can be improved to give cleaner valid markup, and reduce problems with the IE box model, and make it much easier to code, with as much reusable framework as possible.

Contents

  1. Current method
  2. Analysis
  3. Simple Examples
    1. List
    2. Paragraphs
    3. Select element
    4. Mixed content
  4. How does it work?
  5. Advanced Methods
  6. Advanced Examples
  7. Multiple boxes?
  8. Boxes within boxes?
  9. Summary and other advantages
    1. Final Code
  10. Even More Advanced

Current method

Analysis

The current method is un-semantic, composing purely of mostly-un-nested divs. The actual simplicity of it is actually to be admired. However, we can make the markup more meaningful, which is obviously the purpose of HTML.

Firstly, looking at the site shows that there seems to be 3 sizes of boxes, referred by their names in the current CSS as b, n, and x (there's also a c type, but it's the same width as n, so we'll ignore it for now). b has a width of 180px, n is 515px wide, and x is 710px wide.

What I want to achieve is a consistent method of implementing any of these boxes, for any type of content that may fill it.

The boxes are made up of 3 parts - the top, middle and bottom. The top and bottom use an image each for the curved borders, while the middle uses yet another image for some boxes, or plain borders for others. I've already shown that using plain borders for the middle section, and merging the top/bottom image into one sprite image and positioning via the background-position property is consistently faster than having up to three separate images.

I notice that each of the current boxes has a title - this is good, as it can marked up correctly as a header, and used as a CSS hook to hang one of our images.

Another thing to consider is IE’s broken box model for IE5.x, which is also seen in IE6 and IE7 when they are in quirks mode. There a few hacks around which we could use, but these may break in future browsers. The much better alternative is a logical one, and is simply that you specify a width for the parent element, and put any padding and margin on the child element. As each of these boxes appear in a defined column, the width is already specified (the div has the class "example" on this page), then we should only need to specify margin and padding inside the boxes.

The class names should be as meaningful as possible. "b", "n" and "x" may mean baby, normal and extrabig to the author, or they may mean something completely different. We could define the boxes using their sizes: box180, box515 and box710. This is usually a bad idea as changing the width property of it may make the name meaningless. However, on this occasion, as images are used, and any new size box would need a new image, it isn't so critical. I do however propose playing safe for the moment, and using the class names of smallbox, bigbox and fullbox as these would make sense to anyone. Other size boxes could include tinybox, mediumbox and halfbox for example. (As you'll see later, this discussion is a moot point, only to highlight an example).

Continuing with class names, I want the structure inside of my box to be identical across all size boxes, making it easier to code.

Simple Examples of a solution

Several boxes, with different types of content (list, paragraphs, form select element, and one with mixed content). The code for each is given in the textboxes underneath each example.

A list - an ordered list, although the list-style-type is set to none.

Latest Events

That's it - just two divs, as opposed to 10 in the current method. One div defines the box, the other defines the contents of the box. In this example, the events are a list, specifically an ordered list (the latest is at the top).

A couple of paragraphs

Jargon Busters

No Messages
No new mail

Last completed OD match…

One slight anomaly is when a paragraph is the last item in the contents. Due to margin-collapsing, the containing div doesn't expand to contain the margin of the paragraph, and so we define a class, that simply removes that margin, avoiding a break in the side-borders.

A form select element

Sort Players

All looking fine here. A test on the select element has also been completed.

A box with all of the above elements included

Mixed Content

  1. Matches OD (WI)
  2. Daily Updates (WI)
  3. Matches OD (ENG)
  4. Matches OD (SA)
  5. Daily Updates (ENG)

No Messages
No new mail

Last completed OD match…

How does it work?

We need to have three boxes, to emulate the top, middle and bottom of the original method. We know we have two parts of one image (the sprite image) to place, and one set of left and right borders.

The boxcontents provide the side borders. Here’s the boxcontents on it's own:

Some content here

The next part is that title, marked up with a h2 header. Each box obviously has something worth showing to be in a box, so the title of the box is important. The h1 element should only be used for the main page title (probably the logo at the top of a non-frames page), so h2 is the next most important. Here it is on it’s own:

Box Title

That leaves just the bottom image of the box, which is given via the background for the box div:

A bit of CSS styles the text, margins and paddings, and bringing the whole box together to avoid any gaps.

Advanced methods

Now this is fine for a small box, and using the same method as above, we can define a bigbox:

Some title

Some content.

As you can see, the structure is simple, and only the class name for the outside div is different. Can we make it even better though?

We know that a smallbox is always contained within a left or right "menu" div that is 180 pixels wide (the only exception is on the rules page, but these nested boxes are accounted for later). A bigbox is always in a left or right column with a width of 515 pixels, and a fullbox is always directly in a div with an id="page".

Why do we need individual class names of smallbox, bigbox and fullbox then? We could just use child selectors to work out which box we've actually got, and insert the correct background. This means that all boxes are constructed in exactly the same way.

Advanced Examples

The same code for each box, but held within different parent elements. The parents have classes on this page, but would be id's in the final version.

Title goes here

Some content that is contained within a box.

Title goes here

Some content that is contained within a box.

Left menu (180px) and a right column (515px).

Title goes here

Some content that is contained within a box.

Title goes here

Some content that is contained within a box.

Left column (515px) and a right menu (180px).

Title goes here

Some content that is contained within a box.

Finally a page wide (in Battrick layout) box.

As you can see from the code below, the boxes themselves are identical in code.

Multiple boxes?

The original layout uses multiple boxes sometimes, particularly with the left/rightmenus. Can we do it with this method? Let’s see:

Jargon Busters

No Messages
No new mail

Last completed OD match…

Battrick

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum id augue eu lorem ultrices pellentesque. Sed sollicitudin sapien sed magna. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla erat. Suspendisse potenti. Ut blandit vehicula enim. Aenean magna ante, condimentum in, nonummy sagittis, posuere id, tortor. Morbi eu purus eget tortor porttitor aliquam. Suspendisse mauris. Donec et lorem. Sed egestas. Aliquam nec magna mollis massa scelerisque commodo. Donec vel mi. Proin a sem sed elit tincidunt scelerisque. Nulla venenatis felis non lorem. Donec ligula. Curabitur bibendum consequat velit. Duis sit amet pede a dolor rutrum sodales. Aliquam eleifend metus. Integer aliquet, augue sed ultricies mollis, felis erat scelerisque dui, quis ornare ligula augue varius nunc.

Aliquam bibendum. Integer suscipit metus vitae diam. In eget mauris. Etiam laoreet nunc nec velit. Aenean nonummy. Curabitur volutpat. Aliquam bibendum dui quis lacus. Pellentesque justo. Aenean vel pede. Fusce quis erat. Aenean quis nunc ut turpis condimentum varius. Nunc mauris felis, dictum vitae, laoreet sit amet, commodo ac, justo.

Looks fine to me.

Boxes within boxes?

The rules page currently has boxes within a box for the Appendix section on the levels. How does that stack with the new method?

Content

Ordered list of contents would go here.

Battrick

Below are the levels for Aggression and Fitness Levels.

Aggression

  1. defensive
  2. cautious
  3. steady
  4. attacking
  5. destructive

Fitness Levels

  1. exhausted
  2. drained
  3. fatigued
  4. low
  5. fair
  6. moderate
  7. fresh
  8. lively
  9. invigorated
  10. energetic
  11. sublime

Within the boxcontents for our rightcolumn box, we specify an innermenu div, then fill it with as many boxes as we want. I've added CSS so that the innermenu is centered. We must also specify a class="box last" on the last box in the parent div, to avoid breaking the side borders (just like with the final paragraph mentioned above). This will also work when putting a column box or menubox into a fullbox:

This is a fullbox

This is a rightmenu box

Paragraph here

Paragraph here

Paragraph here

Floating to the right.

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum id augue eu lorem ultrices pellentesque. Sed sollicitudin sapien sed magna. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla erat. Suspendisse potenti. Ut blandit vehicula enim. Aenean magna ante, condimentum in, nonummy sagittis, posuere id, tortor. Morbi eu purus eget tortor porttitor aliquam. Suspendisse mauris. Donec et lorem. Sed egestas. Aliquam nec magna mollis massa scelerisque commodo. Donec vel mi. Proin a sem sed elit tincidunt scelerisque. Nulla venenatis felis non lorem. Donec ligula. Curabitur bibendum consequat velit. Duis sit amet pede a dolor rutrum sodales. Aliquam eleifend metus. Integer aliquet, augue sed ultricies mollis, felis erat scelerisque dui, quis ornare ligula augue varius nunc.

This is an innermenu box

Centered.

This is a leftmenu box

Paragraph here

Paragraph here

Paragraph here

Floating to the left.

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum id augue eu lorem ultrices pellentesque. Sed sollicitudin sapien sed magna. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla erat. Suspendisse potenti. Ut blandit vehicula enim. Aenean magna ante, condimentum in, nonummy sagittis, posuere id, tortor. Morbi eu purus eget tortor porttitor aliquam. Suspendisse mauris. Donec et lorem. Sed egestas. Aliquam nec magna mollis massa scelerisque commodo. Donec vel mi. Proin a sem sed elit tincidunt scelerisque. Nulla venenatis felis non lorem. Donec ligula. Curabitur bibendum consequat velit. Duis sit amet pede a dolor rutrum sodales. Aliquam eleifend metus. Integer aliquet, augue sed ultricies mollis, felis erat scelerisque dui, quis ornare ligula augue varius nunc.

This is a rightcolumn box

Paragraph here

Paragraph here

Paragraph here

Floating to the right.

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum id augue eu lorem ultrices pellentesque. Sed sollicitudin sapien sed magna. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla erat. Suspendisse potenti. Ut blandit vehicula enim. Aenean magna ante, condimentum in, nonummy sagittis, posuere id, tortor. Morbi eu purus eget tortor porttitor aliquam. Suspendisse mauris. Donec et lorem. Sed egestas. Aliquam nec magna mollis massa scelerisque commodo. Donec vel mi. Proin a sem sed elit tincidunt scelerisque. Nulla venenatis felis non lorem. Donec ligula. Curabitur bibendum consequat velit. Duis sit amet pede a dolor rutrum sodales. Aliquam eleifend metus. Integer aliquet, augue sed ultricies mollis, felis erat scelerisque dui, quis ornare ligula augue varius nunc.

This is an innercolumn box

Centered.

This is a leftcolumn box

Paragraph here

Paragraph here

Paragraph here

Floating to the left.

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum id augue eu lorem ultrices pellentesque. Sed sollicitudin sapien sed magna. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla erat. Suspendisse potenti. Ut blandit vehicula enim. Aenean magna ante, condimentum in, nonummy sagittis, posuere id, tortor. Morbi eu purus eget tortor porttitor aliquam. Suspendisse mauris. Donec et lorem. Sed egestas. Aliquam nec magna mollis massa scelerisque commodo. Donec vel mi. Proin a sem sed elit tincidunt scelerisque. Nulla venenatis felis non lorem. Donec ligula. Curabitur bibendum consequat velit. Duis sit amet pede a dolor rutrum sodales. Aliquam eleifend metus. Integer aliquet, augue sed ultricies mollis, felis erat scelerisque dui, quis ornare ligula augue varius nunc.

Summary and other advantages

I think the method shown above would make templates, or HTML embedded within .asp files cleaner, the markup more structured, simpler CSS, more advanced layouts, and basically be a "better" way of doing things. Four other points are worth noting:

A quick word on the use of the boxcontents class name - we could have used the .box div selector to style the boxcontents div, but this would have styled any other divs within the boxcontents and box as well. Divs nested this deep (perhaps for a form) should have their own id or class to avoid bug-hunting.

Final Code

The structure for any box is:

<div id="[left|right|inner][menu|column]"> <!-- omit this div for page-wide full box, use class instead of id for nested boxes -->
    <div class="box">
        <h2>Box Title</h2>
        <div class="boxcontents">
            Content here - use class="last" on the last paragraph
        </div>
    </div>
</div>

The css for use in the final version is:

#leftcolumn, #rightcolumn, .innercolumn {width: 515px;}
#leftcolumn, .leftcolumn {float: left;}
#rightcolumn {margin-left: 190px;}

#leftmenu, #rightmenu, .innermenu, .leftmenu, .rightmenu {width: 180px;}
#leftmenu, .leftmenu {float: left;}
#rightmenu {margin-left: 525px;}

.box {
    margin-bottom: 14px;
    background: url(xbox.gif) no-repeat left bottom;
    padding-bottom: 1em;
}
#leftcolumn .box, #rightcolumn .box, .innercolumn .box, .leftcolumn .box, .rightcolumn .box {
    background: url(nbox.gif) no-repeat left bottom;
}
#leftmenu .box, #rightmenu .box, .innermenu .box, .leftmenu .box, .rightmenu .box {
    background: url(bbox.gif) no-repeat left bottom;
}
.box h2 {
    font-size: 13px;
    color: #707090;
    padding: 0 0 5px 10px;
    background: url(xbox.gif) no-repeat right bottom;
    height: 2em;
    margin-bottom: 0; /* This reset should be set in the base.css */
    font-weight: normal; /* This reset should be set in the base.css */
}
#leftcolumn .box h2, #rightcolumn .box h2, .innercolumn .box h2, .leftcolumn .box h2, .rightcolumn .box h2 {
    background: url(nbox.gif) no-repeat right bottom;
}
#leftmenu .box h2, #rightmenu .box h2, .innermenu .box h2, .leftmenu .box h2, .rightmenu .box h2 {
    background: url(bbox.gif) no-repeat right bottom;
}

.box .rightmenu, .box .rightcolumn { /* For right boxes in boxes */
    float: right;
    margin: 0px 10px;
}
.box .leftmenu, .box .leftcolumn { /* For left boxes in boxes */
    margin: 0px 10px;
}
.innermenu, .innercolumn { /* For centered boxes within boxes */
    margin: 0px auto;
}
.boxcontents {
  border-left: 1px solid #c0c0c0;
	border-right: 1px solid #c0c0c0;
	padding: 0 10px;
	margin-bottom: -1px;
}

p.last, div.last, .box .box {
    margin-bottom: 0;
}

Even more Advanced

By making the CSS file into a .asp file, and delivering it via a text/css header, you can create CSS variables. This means that the sizes can be extracted to the top of the file, and any calculations (e.g. margin-left=width+10px) can be done automatically.