An Unfinished Symphony

It's about the internet and stuff.

Z-index Oddities: Menu dropdowns overlapped by positioned elements

I use the Suckerfish Dropdowns menu quite often when building large sites and rarely have too many problems with it. However, on one of the sites I'm currently working on there have been quite a few odd bugs – though I should stress that I don't think it's specifically an issue with Suckerfish, rather with nested dropdown menus (that use absolute positioned elements within floated ones) in general.

The most common issue found with this kind of menu is that, in Internet Explorer, relative positioned elements located below the menu on a page will overlap the dropdowns, obscuring them and preventing access to the links as a result. The normal solution for this, and the one most commonly suggested, would be to use a higher z-index on the dropdown ULs. On this occasion, though, increasing the z-index of nested lists within the dropdown menu didn't have any effect – not even when setting ridiculously high z-indexes, nor when also specifically setting a lower one on the positioned element. In the end I was compelled to remove positioning from all elements where I could without it affecting anything else.

That appeared to do the trick, until it was noticed that the issue was still present on some pages of the site despite relative positioning not being involved. After further investigation I discovered that the bug was limited to data tables containing links. Though, as mentioned above, there was no positioning involved. Despite that I kept my efforts to fix the issue focused on positioning and decided to test how various positioning properties affected things. I began, and ended, with static positioning (the default) by targeting all links within tables with the following CSS:

  1. table a { position : static; }

Adding that to the bottom of my IE only style sheets fixed the issue. Thankfully! Unfortunately, things are never quite that simple where IE is concerned and I found that my fix broke an image rollover system used on 2 pages, preventing the images from displaying when the links where moused-over. To try to fix this I set all links in those 2 tables to use absolute positioning which, initially, seemed to work in this case. However, more thorough testing showed that while it fixed it for links above the page fold; all those below the fold would either vanish on mouseover or reposition themselves at the top of the table. Testing with all variations of positioning and link state proved fruitless. In the end the only answer was to fix the menu issue, and consequently the disappearing link issue, leaving IE 6 users without the thumbnail view (the use of zoom: 1; haslayout fix had no effect). Sometimes sacrifices have to be made to ensure a website remains usable for its visitors, no matter how much the site owner wants a given feature to be added.

Up arrow

Redesign

Regular visitors to the site should notice quite a radical change of design here which I'm hoping will make it a bit more visually pleasing. When I first started the site it was, almost literally, just thrown together in a hurry and without a finalised design. This was basically because there were a number of people that wanted the blog up and running and, I think, for me to start posting on it. Some of you may still remember the original look of the site, which was far from complete and so a little bit broken to say the least. After a little feedback I decided not to continue working with that design and came up with a working temporary one instead. Even though it provided everything I wanted from it (functionality, flexibility and simplicity) it was a little uninspiring and I was never really happy with it, despite that it managed to survive for a couple of years.

Simplifying the Interface

What I've tried to do with the new design is keep the important concepts intact – it's still, I believe, functional; it's still flexible, though now within a set limit; and, importantly, it's still simple. In fact I've made an effort to simplify it further. I found certain aspects of the old design were slightly cluttered, notably the links sidebar. In order to de-clutter the link heavy sidebar I separated the archives and external links section into their own pages, with them linked via a new primary menu. I've also used a little PHP and hidden the MyBlogLog widget from everyone but myself.

All in all I think the sidebar is cleaner and more useful while still sharing things that I want to share. Also, perhaps the most noticeable change is the dropping of the third column from the front page. My original idea for that was to allow the front page of the site to show the latest post in full whilst also showing the next 5 or 6 most recent posts, but rather than overloading the page with too much content these recent posts would just have excerpts showing on the front. The old design did achieve that fairly well, however the extra column meant that the front page would always seem a little cramped. It's also not necessary to have a third column in order to provide direct access to that content from the front page, so it got dropped.

New Sections

I've added a few extra sections to the site where I can provide supplementary information, such as an accessibility statement and privacy policy, including an about page. At the moment the about page is a bit bare; I do intend to put something in there at some point, hence its inclusion, however I haven't decided on what exactly I want to say. I've also extended the subscription page to include information about my feeds, feed readers and feed aggregators along with the original email subscription option that I've carried over from the previous version. There's also a contact form, just in case.

Ironing out the Issues

As with any project, there have been issues to resolve (I'm talking specifically about coding issues at this point).

PHP Issues

One of the things I wanted was for the archives page to show each category with all the posts for that category, to be able to reorder the categories, to be able to show the date of each post adjacent to the link to the post and to be able to structure markup how I wanted. One of the great things about WordPress is its ease of templating, and to that end the codex provides details of the variety of template tags available for this, however those available for templating category listings didn't quite meet all of my requirements. This is where Sarah came in with a bit of help, well a lot of help, providing me with the PHP needed to pull the required information from the database in the way that I wanted. She also helped me write the PHP for my contact form, in the process helping me to add in fields checking for spammers, and also code to check that those fields had been completed appropriately.

The site used to use an old version of the Subscribe2 plugin which I held off from upgrading to the amount of work it would have taken to get a newer version to work with the existing theme. A new theme has meant that was no longer a consideration, and so I upgraded to the latest version of Subscribe2. It was only when I uploaded, and set live, the completed theme and upgraded plugins at the weekend that a few issues came to light. Basically the plugin only partially worked on the live site, with new subscribers receiving an email containing a link to confirm the subscription, but the link going to a blank page and the subscription not being confirmed. After a lot of reading through the plugin code, and with Sarah doing a number of tests, we found that there were three functions responsible for the confirmation process – commenting out the call to one of these functions allowed the confirmation to go through and the appropriate confirmation page to display – just in a very broken state as a number of scripted components failed to work on the page. It had, by that time, occurred to us that it was an issue with using customised permalinks on the site along with the way the plugin takes over an existing page that it rewrites with the confirmation – instead of doing this successfully the page was being redirected to the real permalinked page, causing the confirmation to fail. Once we had tested that this was the case, by resetting permalinks to the default method, it didn't take much to discover the real cause – a conflict between Subscribe2 and the Permalink Redirect plugin. This issue hadn't existed with the previous version of Subscribe2 that I'd been using, so something that has changed caused the conflict – the process of taking over an existing page from the database, rather than using its own dedicated one like the old version did. It's probable that the new method makes it easier for the plugin to be integrated with a theme and so it's an acceptable change in the grand scheme of things, but unfortunate that it results in a conflict. To fix it I dropped the other plugin.

CSS Issues

While differences in browser rendering continue to exist there are always going to be display issues when switching between those browsers. The star browser was Firefox, getting things right first time and according to standards. Internet Explorer 7 had a few minor issues, and IE 6 a few more, however these were relatively simple to fix with a few changes in margin, width and position settings in their own respective style sheets linked via conditional comments. In Internet Explorer 5.5 it looked like a bomb had hit it; that browser couldn't handle a fair bit of the CSS and rather than spend too much time on an obsolete browser I changed a number of things and fixed the width. I basically just wanted to make sure the site would be usable rather than trying to precisely reproduce the design.

Quite surprisingly I had a few strange problems in Opera 9.20, surprisingly because Opera is at least as standards compliant as Firefox if not more so. However there were several oddities that didn't seem to have an easy fix, or at least not a fix that could be achieved simply by tweaking the CSS without those tweaks affecting other browsers. Those issues included:

  • displaying the sponsor links at the correct size until the page finished loading, then the text mysteriously shrinking. As these used the same markup and CSS as the other links in the sidebar there was no easy or logical way to fix the problem without affecting the other links.
  • text marked up as paragraphs within the content area would magically jump to the right once the page loaded, leaving a small fragment of text behind (a few characters from the last line of each paragraph, chopped off at the top). Again, there was no simple fix without it affecting the positioning in other browsers.
  • text link styles were overridden with the browser default ones, again without any logic that I could see. It's possible that one of the settings in my browser profile caused this issue, but I'm not familiar enough with the browser to track it down – so I needed to find another fix.

It's likely that the first two issues were caused by the combination of scripts used on the page, for example the sponsor links are generated by scripts. However as it wasn't feasible to remove those scripts anyway I decided not to test the theory by disabling them on a live site (the issues weren't apparent in my local testing copy). Due to the prospect of a CSS fix affecting other browsers I had to find a hack or filter for Opera, much as it pains me to use them now that it's clear we can control the real problem browser (Internet Explorer 6 and under) using conditional comments. However these issues needed an Opera specific fix and, after a bit of searching on Google, I found a way using an @media declaration to target Opera:

  1. @media all and (min-width:0px) {
  2. head~body p {
  3. margin-left : 0;
  4. }
  5. #content a, #content a:link, #content a:visited, #skipper a:link, #skipper a:visited {
  6. color : #00303e !important;
  7. }
  8. #content a:hover, #content a:active, #content a:focus, #skipper a:hover, #skipper a:active, #skipper a:focus {
  9. color : #870000 !important;
  10. }
  11. #sidebar #links55315 a {
  12. font-size : 11px;
  13. }
  14. }

The combination of the "@media all" and the "and (min-width:0px)" in line 1 of the code above targets Opera fairly specifically – apparently it has also been shown to target Pre-release versions of Safari too. I had no way of testing this, however I felt it was safe to use the method as I was just emphasising already existing styles rather than trying to impose different ones. Line 2 very specifically targets all paragraphs, overriding any other rules that may be conflicting. Line 3 sets the left margin for all paragraphs to zero (even though this had already been done in the main style sheets), while Line 4 closes the rule set opened in line 2. A quick test in Opera showed that the method worked successfully. Lines 5, 6 and 7, and lines 8, 9 and 10 were used to fix the link colour change, while 11, 12 and 13 were used to fix the resizing of the sponsor link text – using a pixel unit instead of ems was what was needed there. The final line closes the whole thing. That discovery came courtesy of the Tanrei Software blog where there's a useful article on using media selectors for browser targetting.

Other Issues

Rather than use a mass of extra markup and images I chose to use Alessandro Fulciniti's NiftyCorners Cube script for the curved corners, so users without javascript enabled will see the site with square corners. Users with javascript may also have some issues, there's a slight lag in the page load time as the script runs through the targeted elements in order to set the curved corners. It's also possible that the script contributes to the paragraph jumping in Opera, though I've never seen this happen in other sites that I've used the script on.

I use a plugin that dynamically adds classes to various links in order to add an icon to identify the target type (such as an arrow pointing away from a box to indicate external links). One of the icons used was for links to Wikipedia which consisted of a small icon of the Wikipedia logo. However it was hard to distinguish that icon from the surrounding text, so it was removed.

I wanted to use an image of an upwards pointing arrow for my back to top links, but without all of the images being background images (otherwise there would have been no actual content for the links). I achieved it using a combination of foreground and background images with the following markup and CSS:

The HTML
  1. <div class="up">
  2. <a href="#skipper" title="Back to top">
    <img src="http://www.ap4a.co.uk/wp-content/themes/mannequin/images/up.png" width="16" height="16" alt="Up arrow" /></a>
  3. </div>

The markup simply creates a div as a container element for the image used as the default-state up arrow and the actual link back to the top of the page.

The CSS – part 1
  1. div.up {
  2. float : right;
  3. margin : 5px 10px 0 0;
  4. padding : 0;
  5. width : 16px;
  6. height : 16px;
  7. }

The first part of the associated CSS sets the dimensions of the container div to match the size of the image it contains and positions it where I want it on the page (relative to its own container).

The CSS – part 2
  1. div.up a, div.up a img {
  2. display : block;
  3. padding : 0;
  4. margin : 0;
  5. }

Part 2 of the CSS sets both the image and the anchor around it to be block level. This corrects Internet Explorer 6's behaviour of adding a 3px space beneath inline images (which is the space preserved for text descenders). It also allows the full area taken up by the image to be a clickable part of the link.

The CSS – part 3
  1. div.up a {
  2. background : url(images/up2.png) no-repeat center bottom;
  3. position : relative;
  4. width : 100%;
  5. height : 100%;
  6. text-decoration : none;
  7. cursor : pointer;
  8. }

This code sets the link to 100% width and height of the container div to complete the process started in the previous rule set, which allows the full area of the image to be clickable. It also sets the positioning to relative to allow the contained image to be absolutely position within it, and the first line sets the background to be the hover state version of the image. The final 2 lines turn off the underline added to links and ensure that the proper cursor style is used.

The CSS – part 4
  1. div.up a img {
  2. position : absolute;
  3. top : -5px;
  4. left : -5px;
  5. border : none !important;
  6. }

Part four positions the foreground image within its containers so that it precisely and completely covers up the background image. It also makes sure that no border is added.

The CSS – part 5
  1. div.up a:hover img, div.up a:active img, div.up a:focus img {
  2. visibility : hidden;
  3. }

The final rule set is responsible for removing the foreground image when the link is hovered over, revealing the hover state background image. It works as intended in Firefox, IE 7 and Opera 9. In IE 5 and 6 the change in state doesn't work, and IE 5 also needs a slight change in the positioning to cover the hover state image.

No doubt there'll be other issues to find, and they'll be fixed when they are. I'm expecting there to be one or two in Mac browsers, but as I haven't been able to test in them (the Mac testing services I normally use have been broken when I've visited recently) I haven't been able to find them. If you're a Mac user and do find issues, please let me know and I'll do my best to resolve them, thanks.

Up arrow

Firefox window resize bug and other annoyances.

A few months ago I asked if anyone had noticed a bug in Firefox that caused the vertical scrollbar to vanish when resizing the browser window to 800 pixels wide. I never received any answers to the question – and I never thought much more about it as it didn't affect my browsing and I could still test sites at that width, just without a scrollbar. However, after updating to Firefox 1.5.0.4 on Friday the bug mysteriously reappeared, and this time it seemed more severe. This time it was affecting my ability to test sites, and so this time I did a little more than just ask about it on here.

A screenshot of Firefox's window resize bug in action
Thumbnail view of Firefox's window resize bug in action.
Rather than just losing the vertical scrollbar I now lost the horizontal one too, when one should be there – which would be every time for content that wasn't fixed to fit in under 800 pixels wide as liquid layouts, such as the one on this blog, failed to resize too.

I did a search on bugzilla to see if there were any previously filed reports and found one dating back to 2003 which has identical symptoms to this one (as in it's the same bug, 3 years and several browser versions later). It turns out that the problem is a result of the browser incorrectly tying viewport width in with the status bar width, so if your status bar contains a large number of icons, or a series of longer ones, you are likely to encounter this issue. In order to temporarily fix it I've had to disable the status bar icons for a number of my browser extensions so that they all fit at an 800 pixel wide resolution. This is far from ideal and diminishes the usefulness of my browser as a development tool, not to mention affecting the single biggest factor (in my opinion) in Firefox's commercial success – it's extensibility.

How a bug with such severe outcomes as this can survive for three years and across multiple updates and upgrades I don't know – perhaps it's down to its severity being stupidly marked as minor?

On a different note, I also think that the absence of an installation rollback feature for Firefox is a major omission that should be rectified ASAP. At this moment in time the only viable (yet risky) option for repairing a failed install/update, including automatic updates, is to overwrite the existing installation. For example if the install fails due to a corrupt installer package you need to overwrite it with a different copy, or less desirably, a previous version. How come? As mentioned, there's no rollback feature and system restore often fails to correct the problem – I know, I tried it myself on Friday when the first update attempt left me with nothing more than an empty title bar:

Firefox 1.5.0.4 following automatic update using a corrupt installer package.
Firefox 1.5.0.4 after automatic update used a corrupt installer package.
My less than functional copy of Firefox, consisting of an empty title bar and a non-working close window button.

Fortunately overwriting with a different installer worked, if it didn't I'd have needed some way of getting hold of an earlier version – not too easy when the Firefox download page only contains links to the latest version and Evolt's latest archive version is 0.7.1 – the average user wouldn't think to change the version number in the download URL at Mozilla. Also, I think the idea is for Firefox to not only be a first choice browser, but eventually to become the only choice for the average user? Like Internet Explorer is currently for millions of people – so what would have happened if that was the case? I'd have been left completely browserless and unable to find a way back to Mozilla to download a different copy of the installer package.

These are the kind of issues that Mozilla need to urgently address if they want to see their market share continue to rise, failure to do so could well lead to them losing it. The world is a fickle place and in my opinion the main factor keeping Firefox ahead of Opera at the moment is its extensibility, but even that has lingering flaws as is mentioned above.

Up arrow

Safari's margins for error

I was reminded earlier yesterday about a post I've been meaning to write for over a month, when I was given a little feedback on how this site displays in Mac browsers. Whilst the site rendered as expected in Firefox/Mac, there was an issue with the left hand margin on the far left column which consequently was hugging the edge of the browser window in Safari. This came as a bit of a surprise to me, as I'd spotted the issue a month before when using iCapture and thought that I'd fixed all instances of it – seems not. The original problem was far more dramatic than the window hugging left column that I saw today, whereby a couple of the columns had lost their margins and were hugging their neighbour(s)' borders.

A view of this site, and the collapsed margins, in Safari
View of ap4a.co.uk in Safari web browser before fixing CSS
As you can see, the left hand edge of the first column is hugging the edge of the browser window; whilst the margin set between the left and middle column have collapsed completely, forcing the two columns to align up against each other.

After a review of my CSS I couldn't see any obvious problems – all columns had margins set in percentages, designed to be flexible along with the rest of the layout, and this had proved robust in all the windows browsers which I had tested on including, after a slight modification, in IE. It could only be that it was that slight modification which was the issue. In order to get IE to play nicely I'd had to reduce the margins very slightly, by 0.1% from 1% to 0.9% and it appeared that Safari didn't like non-integer percentage values. In order to check that this was really the case I ran several tests with various sized margins using percentage units alongside controls using ems – ems beings chosen as, like with percentages, decimals are allowed. To view the test page visit Safari Web Browser Margin Tests

Safari Browser – Test One: margins on floated elements

Test One: control example using em-based units
Margin test using ems - this is a control test
This control test consisted of four equal sized, floated divs being separated horizontally by em-based margins ranging from 0.2em up to 0.8em. As can be seen in the image taken from a screen capture of the Safari Web Browser Margin Tests the margins are working as they should be.
Test One: test example using percentage-based units
Margin test using percentages, not a control test
This test consisted of four equal sized, floated divs being separated horizontally by percentage-based margins ranging from 0.2% up to 0.8%. As can be seen in the image taken from a screen capture of the Safari Web Browser Margin Tests the margins are collapsing together as described above.

Safari Browser – Test Two: margins on unfloated elements

In order to rule out the possibility that this was a float bug, rather than one related to using non-integer percentage sized margins, it was necessary to conduct a second test on unfloated elements.

Test 2: control example using em-based units
Margin test two, using ems - this is a control test
This control test consisted of four equal sized, unfloated divs being separated vertically by em-based margins ranging from 0.2em up to 0.8em. As can be seen in the image taken from a screen capture of the Safari Web Browser Margin Tests the margins are working as they should be.
Test Two: test example using percentage-based units
Margin test two, using percentages - this is not a control test
This test consisted of four equal sized, unfloated divs being separated vertically by percentage-based margins ranging from 0.2% up to 0.8%. As can be seen in the image taken from a screen capture of the Safari Web Browser Margin Tests the margins are still collapsing together.

Safari Margin Tests: Summary

As with any browser, despite it's strong adherence to web standards, Safari has its share of bugs. As a result it can't be ignored during the testing phase of site development, which further emphasises the need to test in all possible browsers on all operating systems available to you. If, like me, you don't have a Mac to test sites you might think testing in Mac only browsers is an impossible task, it isn't. There are a number of services available to help with the task, some free such as iCapture, whilst others are commercial. There's also a number of places to download older versions of the browsers that you might already have on your computer, such as the browser archive at Evolt.org.

Up arrow

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