I apologize for the absence of posts recently. I’m not dead! I just thought I’d go for a walk. I was feeling the pressure to be funny constantly, so I’ve contracted with Bobcat Goldthwait to ghostwrite my blog posts for me. Umm, I-I-Arrgh, I want a yacht!
During the hiatus, I’ve also been redesigning my web site. Superficially it looks similar, but under the hood it’s now almost entirely hand-coded (with Smultron). The only iWeb-generated code I kept was the JavaScript photo slide show. The benefits of the redesign are that the pages should load faster, and it’ll be easier for me to update the content, as I just did by adding a link to Mac OS Forge, which has finally emerged from its beauty sleep.
In honor of our new site styles, the subject of this post will be CSS. Sorry, folks, one cannot live on Cocoa alone! One also requires marshmallows, and Fritos. You may have heard of collapsing margins, which occurs in a number of contexts, for example, on election day. It also occurs when the bottom margin of a block-level element on a web page adjoins the top margin of another block-level element. The two margins collapse, and the length of the displayed margin becomes the length of the larger of the two adjoining margins. This can be useful, because typically you want a minimum margin around a paragraph of text, and you want a different minimum margin around a heading, but you don’t want a huge gap between the heading and the first paragraph. (Unless you’re trying to turn 8 pages of actual writing into a 15-page term paper. I know who you are, slackers! I was a teacher. Your grade will reflect your ef-fort.)
What you may not realize is that collapsing margins also occurs when the top margin of a block adjoins the top margin of its parent block. If you load the following HTML in a browser, such as Safari or Camino, you’ll see a purple box at the top of the window.
<html lang="en-US">
<head>
<title>Collapsing Margins</title>
<style type="text/css">
body {
background-color: #000000;
margin: 0;
color: #cccccc;
}
#all_content {
background-color: #590079;
margin-top: 0;
margin-bottom: 0;
margin-left: auto;
margin-right: auto;
width: 40em;
height: 40em;
}
p {
margin-top: 1em;
margin-bottom: 1em;
}
</style>
</head>
<body>
<div id="all_content">
</div>
</body>
</html>
This is to be expected, because body and all_content both have top margins of 0. However, if you add a paragraph, <p>This is a paragraph.<p>, inside the element all_content, something unexpected happens. Instead of the purple box at the top of the window with the paragraph spaced from the top of the box, you see the purple box spaced from the top of the window with the paragraph at the very top of the box.
The margins of the paragraph are supposed to be calculated relative to its containing block, which in this case is the element all_content, so you would expect that the margin should appear between the paragraph and the box rather than between the box and the top of the window. The reason the opposite occurs is that even though the box has a top margin of 0, the top margin of the box and the top margin of the paragraph are technically adjoining, which means the margins collapse, and the one true margin becomes the larger of the two top margins. Since margins are transparent, the black background shows through.
The CSS specifications for collapsing margins are, to put it frankly, idiotic. Or to put it more tactfully, they’re insane. Who in the world wide web would want the top margins of parent and child blocks to collapse? I gave the paragraph a non-zero top margin because, well, I wanted it to have a non-zero top margin! I don’t blame the browser developers for complying to the standards; web designers demand and expect the browsers to be standards-compliant. Rather, I blame the standards developers for developing substandard standards. I can’t imagine what they were thinking. Anyway, the workaround for this bug, as I shall call it, is to give the parent block, in this case all_content, a non-zero border-top or padding-top. If the parent has a border or padding, then the top margin of the child does not adjoin the top margin of the parent, the margins do not collapse, and all is right with the world again.
Speaking of standards-compliance, I used to consider Mozilla’s Gecko, the rendering engine behind Camino and Firefox, the standards king. Perhaps it was, in the early days of Safari. I believe that Gecko has lagged behind while WebKit, the rendering engine underlying Safari and Vienna, among others, has caught up and surpassed it. While testing my web site in Camino, I ran into a couple of problems. First, Gecko doesn’t handle the inline-block display property. This bug has been open since 1999. I would advise web designers not to use inline-block if they want their pages to display properly in Gecko browsers.
Second, there is a bug, open since 2004, in how Gecko calculates percentage margins for a float with width: auto. You can see this by comparing how my résumé looks in Safari and Camino, under the “Degrees” heading, for example. (Is this a ploy to get you to read my résumé? No, just a happy coincidence.) Percentage margins are supposed to be calculated relative to the size of the containing block, but Gecko calculates them relative to the size of the float, so that the width of the margin is a percentage of the sum of the widths of the float and margin. This makes the margin far too small. My workaround, as you can see in the HTML source, was to increase the margin’s percentage size somewhat. It still looks too small in Camino, but I don’t want to make it too large in Safari. Although I could have used a table in this situation rather than floats, it made much more sense semantically to arrange the content by columns rather than by rows.
I hope that you enjoyed my rants, err, tips. I promise to talk about Cocoa programming in the next post. I also promise to lower taxes, raise spending, balance the budget, ask not what my country can do for me, fear nothing but fear itself (that is, the form of fear, not those shadowy particular fears), put a chicken in every pot, a car in every garage, and a kitten in every lap. Of course, this all depends on what the meaning of the word “I” is. I want a yacht. Thank you very much. Argh.
I noticed this stupid collapsing behaviour just three days ago in the same context as your example, but I didn’t understand where it came from. Thanks for the explanation. I wonder what convoluted case made them think we would want such a thing to happen.
I need some help with the Asktheseguys wordpress theme..
I can't figure out how to get the header and ad bar at the top to go all the way across the screen.. Or better yet, how I can place an ad box in the empty space at the top right.
I can usually figure this stuff out easily, but can't find anything in the CSS that will make it work..
Anyone have any ideas?
The reason that margins collapse between child and parent is the same as the reason they collapse between siblings. Consider the following XHTML2-like markup:
Text
You want to give your section a minimum margin, and you want to give your paragraph a minimum margin, but you don’t want a huge margin at the beginning of a section if it happens to start with a paragraph (instead of, say, a table).
Note: If the tags above got treated as markup, the example is:
<section>
<p>Text</p>
</section>