An Unfinished Symphony

It's about the internet and stuff.

Introduction to the CSS Box Model – part two

Internet Explorer and its Broken Boxes

In part one we looked at the CSS box model, how it works, and how we can manipulate it to achieve our design aims. In this article we need to look at what can go wrong when, despite its simplicity, a browser doesn't know how to use the model correctly, and how we can compensate for it.

To summarise the main problem with the box model – Internet Explorer versions 5.01 and 5.5 both use a broken box model; that is they don't use the box model that will produce the neat, precisely dimensioned, boxes that we looked at in article one. Instead of defining the width setting as belonging to the box contents IE 5x was built to use width for setting the overall boundaries for the content area, plus the padding area, and the border. Considering that the CSS specifications are quite clear on how this setting should work it's quite remarkable that the engineers responsible for the Windows implementations of IE 5x would make this error – but they aren't alone. Not only does IE 5x for Windows use the broken box model but, unless you are careful and prevent it from doing so, IE 6 can, and very often does, use the same model as its predecessors.

To be fair to Microsoft the model used for IE 5x is quite a logical one. If we remember our previous explanation for the box model and how we compared a CSS box to a cardboard one we can begin to see how easy it would be to assume that the IE 5x way is the right way. If we were to look at a cardboard box and ask someone to tell us how wide it was they'd measure the external width of the box, from one outer border edge to the other. They wouldn't open it up and measure the free inner space. IE 5x was engineered to do just that – but it's very wrong to do so, not just because it's against the specifications but also because it removes a degree of control over how we are able to manipulate our boxes. A loss of control is usually a bad thing, and it is here too. All that wouldn't be so bad, though, if all of the other browsers decided to follow that lead, at least there would be consistency of implementation. That, however, would require dozens of software groups to reproduce an error made by one of their competitors rather than taking their guidance from the standards body that created the box model specification in the first place – fortunately, for the future of standards, they didn't.

So, what's the real problem with this box model?

That's quite an easy question to answer – take a look at any web page on any site, it has a width that is constrained by the width of the available viewing space (the viewport), which is itself limited by the size of your monitor and monitor resolution. Due to this constraint we have clearly defined boundaries for our design area. If we overflow from these then part of our page spills over and off the page – this most often leads to the need for horizontal scrolling, but in some circumstances it can mean that the overflowing section is completely inaccessible to the viewer. I'm confident that you will agree that that's a bad thing, so we need to make sure that doesn't happen to us. The most common resolutions used are 800px wide by 600px high, and 1024px wide by 768px high, with 80-95% of all internet users having one or the other in an almost equal distribution. This means that we need to set ourselves a page limit of 800px wide if we hope to ensure that as many users as possible can see our page without the need to scroll, and without the need to overly limit our available design space. While many designers opt for this fixed-width page limit some choose to have a flexible/liquid width design that can stretch to fill more space and others choose to accept the scrolling and design for users with a higher resolution. It's not for me to tell you which type of designer you should be, nor am I going to try to.

A more detailed look at IE 5x's broken boxes

Let's review one of the rule set examples given in article one:

  1. img {
  2. width: 210px;
  3. height: 150px;
  4. border: 1px solid black;
  5. padding: 0;
  6. margin: 5px;
  7. }

In the above rule set we defined the properties for an image and it's associated box. We gave it a width, a height, and set its padding, border and margin properties. Images, however, tend not to cause us too many problems, after all many of us omit the width and height settings from the style rule, allowing the image's inherent height and width properties to impose themselves on its containing boxes. In order to properly use the box model in a way that we are likely to see IE 5x break our boxes we need to use an element that doesn't have its own inherent dimension settings. To that end we'll use paragraphs as our rule set targets. Most of you will already know, but for those that don't – the HTML mark-up for a paragraph is <p> – and our selector is a p.

  1. p {
  2. width: 180px;
  3. height: 180px;
  4. border: 1px solid black;
  5. padding: 10px;
  6. margin: 10px;
  7. background: #328DAF;
  8. color: #000;
  9. }

Here I've created a very similar rule set for our p selector as the previous one for our image selector. This gives us a 180 pixel by 180 pixel square paragraph, with 10 pixels of padding surrounding it and a 1 pixel, solid black border around that. Surrounding the whole of this is a 10 pixel margin keeping other elements away from our bordered paragraph. I've also given it a background and text colour so that you can copy and paste the rule set into your own style sheet and exactly reproduce the following image using CSS.

Graphical depiction of the CSS box model applied to a paragraph of text

That image was made by applying the above rule set to a paragraph of text on a web page viewed in Mozilla 1.6 and then a screen shot pasted into a graphics editor. As you can see we have a nice neat 180 pixel square block of text with, as specified in the CSS specifications, a 10 pixel padding space around it, and then our single pixel black border and our margin.

If we look at the same paragraph in IE 5.5 we can see the difference in how our dimension settings are used and abused:

Graphical depiction of IE5x's broken box model applied to a paragraph of text

We can clearly see the difference – the IE 5.5 version is narrower than the Mozilla version. In fact it's exactly 22 pixels narrower – the sum of the left and right padding, and the left and right border dimensions. You'll also notice that the height of the box has stretched, but that's another IE bug and one that we won't discuss here.

The combined width of our content width, padding and borders totals 202 pixels, and if we measure from the left border to the right of the Mozilla rendered version that's just what we have and is in line with the CSS 1 specifications. However if we were to take the same measurement using our IE 5.5 rendered version that width would be 180 pixels, equivalent to the width setting given in the rule set. However, as we've already discovered width in CSS terms equals content width, and not border to border width. So IE 5.5 is very wrong in it's implementation, and when we design our pages to fit in a set space we need to know that all browsers are going to show that same space as being filled by our beautiful design and content.

So how do we manage to use the box model in IE 5x?

Fortunately for designers all over the world a number of methods to fix IE 5's broken boxes have been devised. Most of these being thought up by Tantek Celic who was also the head of the Microsoft team that produced the Tasman rendering agent found in the version of Internet Explorer 5 that Microsoft produced for the Macintosh – it also happened to be the first browser to offer full CSS level 1 support, something that no version of Internet Explorer for Windows has achieved yet, including IE 6. The most widely known box model fix available is the Tantek Hack, or Box Model Hack. We'll review that later in the article, along with several of Tantek's more recent fix discoveries. First, though, we'll have a look at several simpler fixes and discuss the pros and cons of their use before moving on to the more effective solutions devised by Tantek.

Fix 1: Avoid setting widths, or borders and padding

The problem with IE5's box model is that it misinterprets width settings. If we didn't set a width we could avoid the issue altogether. It's sometimes possible to do this, as mentioned previously in regards to images. Occasionally we can also get away with it when using boxes for other purposes. If you can, then do – it'll allow for cleaner more semantic mark-up (cf. fix 2) and cleaner CSS rules. If it's not possible to avoid using a width setting, it may be possible to avoid using borders and padding. Before creating the rule set for an element think – does it need a border? If not then don't use one, and don't use any padding; if padding is required you can always simulate it using the margin setting (remember, margins aren't affected by the broken box model, only borders, padding and widths). If both a width and border are required then this fix won't work for you, but one of the others may do.

Fix 2: Use nesting

Most designers are familiar with nesting elements, it's been in practice since the first days of using tables for laying out page designs, and it's still in use today both with tables and CSS. The difference with doing it with CSS is that it doesn't bloat a web page nearly as much. Whichever way you go it'll always be necessary to use some nesting of elements – for example a paragraph set within a container, or a series of link sets within a navigation bar. Nesting is essential to modern page design, and it can help us out with IE 5's broken box model too. Consider the following XHTML mark-up and CSS rule sets:

  1. The CSS
    1. #outer {
    2. width: 202px;
    3. margin: 10px;
    4. }
    5. p {
    6. border: 1px solid black;
    7. padding: 10px;
    8. background: #427C1B;
    9. color: #000;
    10. }
  2. The XHTML
    1. <div id="outer">
    2. <p>Some Content</p>
    3. </div>

Here I've split the box settings up into 2 separate rule sets and applied the rule sets to a div and a paragraph, then nested the paragraph within the div. As you can see the "outer" div has the width and margin settings applied to it, while the inner paragraph has the borders and padding but no width setting – it doesn't need it as it will stretch to fill the box created by the div that surrounds it. You'll also need to note that we've had to use a width of 202px, rather than 180px, so that when the inner paragraph stretches to fill the outer div the combined width of content, borders and padding comes to 202px, leaving a content width of 180px. It produces the following results in Mozilla and IE 5.5 respectively:

Graphical depiction of fix 2 as displayed in the Mozilla browser
Graphical depiction of fix 2 as displayed in Internet Explorer version 5.5

As you can see the widths of the boxes are the same – we've overcome the broken box model with a very simple workaround. There are issues with this method, however, at least if you're concerned about using clean, semantic XHTML mark-up. The issue being that it isn't clean, at least not as clean as it would be if we didn't have to overcome poor browser implementations of standards by dropping our own a level. That aside, I still use this method to a limited extent on pages that I create, for elements such as header bars where the need for further nesting of elements is limited. I limit the use simply because applying the method to all boxes on my web pages could potentially double the amount of mark-up used, in some cases more so, and doing this totally defeats the object of leaving tables behind and using CSS and XHTML for laying out a web page design. So, it's a useable workaround in some circumstances, but what about other circumstances where the nesting could lead to excessively bloated mark-up? See fixes 3 to 5 for that answer:

Fix 3: The Box Model Hack

As mentioned earlier, the Box Model Hack was devised by Tantek Celic, an expert in CSS, creator of the rendering engine in IE5/mac and a contributor to the CSS level 2, 2.1 and 3 specifications. Considering his obvious interest in CSS it's no surprise that this fix relies solely upon CSS to be achieved. You may want to pause for a breath at this point, as it's going to get interesting 🙂

With his in-depth knowledge of CSS and the way browsers work, notably those produced by his employers, Tantek was able to see a use for, and find, other bugs in IE 5's CSS capabilities, and turn this to our advantage. He noted that Internet Explorer 5 for windows had a number of CSS parsing bugs which were able to confuse it and cause it to stop reading a rule set at a certain point. Compare our earlier rule set with our Tantek hack version, both included below (minus the height setting):

  1. Our original rule set
    1. p {
    2. width: 180px;
    3. border: 1px solid black;
    4. padding: 10px;
    5. margin: 10px;
    6. background: #328DAF;
    7. color: #000;
    8. }
  2. Our Tantek Hack rule set
    1. p {
    2. width: 202px;
    3. border: 1px solid black;
    4. padding: 10px;
    5. margin: 10px;
    6. background: #328DAF;
    7. color: #000;
    8. voice-family: ""}"";
    9. voice-family:inherit;
    10. width: 180px;
    11. }

Remember earlier when I mentioned that our border to border dimensions should total 202px? Well we use that knowledge here in creating two separate width settings – the first one (202px) is for IE 5x, the second is our real one of 180px for browsers that get the box model right. The way it works is that IE5 reads the rule set, sees that it needs to set a width of 202px, does so then takes the border and padding dimensions off that width to leave a content width of 180px. IE 5 then stops reading the rule set at the point of the added hack. Luckily most of the modern browsers that get the box model right don't have that same parsing bug and are able to continue to read the rule set until they get to the second width setting – which then overrides the first one to set a 180px wide content section as it would do in the original rule set. There are one or two issues with using this hack though. One is that using it means that you are using aural CSS style rules, so you can't validly set a non-aural media type for your style sheet. If you do set one then your CSS will be flagged as not being totally valid by the W3C CSS Validator when using it to validate your HTML page. It'll validate your style sheet in isolation as the media type is set within the HTML page and not the style sheet. To get around this you have to make your web page less accessible by omitting the media type attribute from the link to your style sheet.

There's another problem – not all browsers that can do the box model right can get past the hack. Some versions of the Opera web browser have the same parsing bug as IE 5 does, and so we are left needing another fix – fortunately it's a simple one. IE 5 doesn't recognise CSS 2 level selectors, not surprising as it gets a fair bit of CSS level 1 wrong too, and so this can be exploited by using a CSS 2 selector to reapply the correct width setting for Opera. We use a child selector to add in this rule set – note: this must immediately follow the Tantek Hack rule set, if you put it anywhere before it then it will be overridden by the 202px width setting that would then follow. There's a second factor for putting it immediately after, and not following any other rule sets – when using the Tantek Hack IE 5 will fail to apply any styles to the target element unless it is immediately followed by what it considers to be a nonsense rule set, it's inability to recognise CSS 2 level selectors makes the following just that: html>body p { width: 180px; }

We now need to combine both parts so that we can see it how it needs to appear in our style sheet:

  1. p {
  2. width: 202px;
  3. border: 1px solid black;
  4. padding: 10px;
  5. margin: 10px;
  6. background: #FF6600;
  7. color: #000;
  8. voice-family: ""}"";
  9. voice-family:inherit;
  10. width: 180px;
  11. }
  12. html>body p { width: 180px; }

With another colour change this gives the following results in Mozilla and IE 5 respectively:

Graphical depiction of fix 3 as displayed in Mozilla
Graphical depiction of fix 3 as displayed in Internet Explorer version 5.5

Another success! It's not all glory though – there's still the issue of the media type selection, sometimes we just have to specify one, but using this hack we can't. It can also add quite a lot to the size of our style sheets when used to correct the box settings for a lot of elements. So what can we do? See fixes 4 and 5, once again courtesy of Tantek Celic.

Fix 4: The Inline High Pass Filter

This is a more complicated fix that, once again, capitalises on parsing bugs within IE 5x. It's intended for use with an embedded style sheet (within the head of a HTML page) and works by stopping IE 5 from being able to read any rule sets that follow it – giving us the chance to override rule sets that we've set specifically for IE 5. Remember earlier when I said that IE 5 can't parse escaped CSS code? Well this fix uses that in conjunction with a nonsense rule applied to an i (italic) selector in order to achieve the effect we need. As we shouldn't be, and hopefully aren't, using the presentational italic (i) in our mark-up it's safe to apply the nonsense rule to it:

  1. <style type="text/css">
  2. p {
  3. width: 202px;
  4. border: 1px solid black;
  5. padding: 10px;
  6. margin: 10px;
  7. background: #FF6600;
  8. color: #000;
  9. }
  10. i {
  11. content:""/*"
  12. }
  13. p {
  14. width: 180px
  15. }
  16. </style>

IE 5 is unable to do anything with the CSS level two property "content" which is only usable with the :before and :after pseudo selectors. So nothing happens when it's encountered. Then when it reaches the escaping it assumes that the value string has been completed, and then encounters the /* which it treats as the beginning of a CSS comment (CSS comments are contained within /* and */ symbols) and is confused into believing the remainder of the CSS is the contents of the comments and stops at that point. Browsers that support CSS level 1 aren't confused by that and so continue on to the next declaration, ignoring the nonsense property/value pair for the i selector. Another success – but using this method means using a page embedded style sheet, doing that means we lose a lot of the benefits of style sheets, notably the ability to have a central repository for all of a site's style rules, ones that can be applied with ease to hundreds or thousands of pages saving a lot of bandwidth expenditure and requiring only one file to be edited to achieve site-wide changes. They're important benefits to lose, so fix 5 is better.

Fix 5: The High Pass Filter

The high pass filter is essentially the same as the inline high pass filter, except we use external linked style sheets, rather than an embedded one. There are one or two minor differences, which need to be explained, as follows. Once again the methodology is seemingly complex when first encountered, but it's relatively simple in practice. Step one is to create a link within the head of our page mark-up to an external style sheet:

  1. <head>
  2. <title>High Pass Filter</title>
  3. <link rel="stylesheet" type="text/css" href="filter.css" />
  4. </head>

Step two involves creating the style sheet filter.css (though you can call it what you wish), the contents of which follow:

  1. @import "null?"{";
  2. @import "realstylesheet.css";

In the same way as the inline high pass filter works, the high pass filter uses escaping to confuse IE 5. IE 5 is tricked into trying to import a style sheet called null. Then the first escaping confuses it into believing that the instruction to import null has been completed, and then encounters the remainder of the string associated with the first @import instruction which appears as a nonsense declaration which it can't continue beyond. IE 5 then takes no further action and ignores the following @import. Browsers that lack IE 5's parsing problems are able to proceed and read the second @import rule, and in doing so import the real style sheet which will contain all the rule sets to lay out your web pages properly. In order to prevent problems with validating your style sheets or with IE5/mac a file called "null" (without a file extension) needs to be created, and to have contents – which just need to be a comment, for example /* null */. As a result of this fix no older browsers will get the real style sheet, which means they will be unstyled. The browsers which are able to cope with this fix include: IE5+/Mac, IE6+/Windows, Netscape 6+, Mozilla and Firebird, Opera 5+ and any other browser able to pass section 7.1 of the CSS1 test suite.

At this point you may be thinking that if you use this method then your pages will be unstyled in IE5 – and if you only use the high pass filter as above, then that will be the case. However it doesn't have to be. CSS places a priority on rule sets based on the order they appear – a style sheet will override equivalent rule sets contained in a previous one, including when linked in the page head. So, in order to have a nicely styled page in IE 5x using this method we have to go on and make another style sheet just for that browser and link to it before we link to our filter.css style sheet. Like so:

  1. <head>
  2. <title>High Pass Filter - IE 5 Friendly Version</title>
  3. <link rel="stylesheet" type="text/css" href="forie5.css" />
  4. <link rel="stylesheet" type="text/css" href="filter.css" />
  5. </head>

We then set our IE 5 version of the rule sets in the forie5.css style sheet, while placing our standards compliant rule sets within realstylesheet.css as mentioned above. Doing this with the following rule sets will achieve the results in the images below:

  1. The "forie5.css" style sheet
    1. p {
    2. width: 202px;
    3. border: 1px solid black;
    4. padding: 10px;
    5. margin: 10px;
    6. background: #CCC;
    7. color: #000;
    8. }
  2. The realstylesheet
    1. p {
    2. width: 180px;
    3. border: 1px solid black;
    4. padding: 10px;
    5. margin: 10px;
    6. background: #FFF;
    7. color: #000;
    8. }

Graphical depiction of fix 5 as displayed in Internet Explorer version 5.5
Graphical depiction of fix 5 as displayed in Internet Explorer version 5.5

We've now managed to correct the box model problem with IE 5x – however, as you will have noticed every fix has its own pros and cons, it's up to you to decide which is the best for you to use depending upon what you hope to achieve. To finish we need to recall a comment I made, about IE 6, very early on in the article – in some circumstances IE 6 will use the same broken box model as IE 5, but not all. In order to prevent IE 6 from becoming buggier than it inherently is you need to ensure that it renders your pages in standards compliant mode. To do this you need to ensure that you use a valid doctype declaration, including the link to the relevant document on the W3C site. If your pages use XHMTL then you may find yourself using the XML prologue – if you want IE 6 to render in standards compliant mode, don't use the prologue as IE 6 gets confused when it's there and so goes into quirks mode, and breaks the box model, also some versions of IE/mac may display a blank page.

Valid HTML and XHTML doctype declarations and an example XML prologue follow:

  1. HTML 4.01 doctype declarations
    1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
      "http://www.w3.org/TR/html4/strict.dtd">
    2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
      "http://www.w3.org/TR/html4/loose.dtd">
    3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
      "http://www.w3.org/TR/html4/frameset.dtd">
  2. XHTML 1.0 doctype declarations
    1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    3. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
  3. The XHTML 1.1 doctype declaration
    1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
      "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
  4. An example XML declaration (prologue)
    1. <?xml version="1.0" encoding="ISO-8859-1"?>

References:

Up arrow

Comments on 'Introduction to the CSS Box Model – part two'

RSS feed for comments on this post.

gravatar
jhon says:

hi i am spain. explore I have a problem with the content is not limited as to explore and I can not tell me that you could fix a greeting and I thank my css.
.general {
margin : 0 auto 0 auto;
width : 790px;
}
* html #general {
margin-left:200px;
padding:100px;
width : 790px;
}

gravatar

Hi Jhon,

Without knowing more about what you problem is, my best guess would be that your second rule set has the wrong selector. Your first uses the class .general as the selector, but the second includes the ID of #general instead (and a scan of your home page shows that the class .general is in use, but not the id of #general). So replace the # in the second selector with a . and see if that fixes the problem. If not please post up a bit more information and I'll see what I can do.

gravatar

[…] version Intermediate version All you ever will want to know about CSS Box Models (dont forget to look at part one of the article […]

Sorry, the comment form is closed at this time.