tags:

views:

726

answers:

7

When you want to add whitespace between HTML elements (using CSS), to which element do you attach it?

I'm regularly in situations along these lines:

<body>
  <h1>This is the heading</h1>
  <p>This is a paragraph</p>
  <h1>Here's another heading</h1>
  <div>This is a footer</div>
</body>

Now, say I wanted 1em of space between each of these elements, but none above the first h1 or below the last div. To which elements would I attach it?

Obviously, there's no real technical difference between this:

h1, p { margin-bottom: 1em; }

...and this...

div { margin-top: 1em; }
p { margin-top: 1em; margin-bottom: 1em }

What I'm interested is secondary factors:

  1. Consistency
  2. Applicability to all situations
  3. Ease / Simplicity
  4. Ease of making changes

For example: in this particular scenario, I'd say that the first solution is better than the second, as it's simpler; you're only attaching a margin-bottom to two elements in a single property definition. However, I'm looking for a more general-purpose solution. Every time I do CSS work, I get the feeling that there's a good rule of thumb to apply... but I'm not sure what it is. Does anyone have a good argument?

+4  A: 

I tend to use a bottom margin on elements when I want them to have space before the next element, and then to use a ".last" class in the css to remove the margin from the last element.

<body>
  <h1>This is the heading</h1>
  <p>This is a paragraph</p>
  <h1>Here's another heading</h1>
  <div class="last">This is a footer</div>
</body>

div { margin-bottom: 1em; }
p { margin-bottom: 1em; }
h1 { margin-bottom: 1em; }
.last {margin-bottom: 0; }

In your example though, this probably isn't that applicable, as a footer div would most likely have it's own class and specific styling. Still the ".last" approach I used works for me when I have several identical elements one after the other (paragraphs and what-not). Of course, I cherry-picked the technique from the "Elements" CSS framework.

Pavling
If you don't mind shunning IE6 you could always fall back on the CSS2 :first-child and :last-child pseudo selectors to do your bidding!
Zack Mulgrew
A: 

I tend to agree with you that the first option is better. It's generally what I like to do. However, there is an argument to be made that you should specify a margin for each one of those elements and zero it out if you don't want to apply it since browsers all handle margins differently. The <p> (and the <h1> tag too I think) will usually have default margins given by the browser if none are specified.

Bryan Friedman
+2  A: 

This going to be driven partly by the specifics of what you're designing for, but there's a sort of rough heirarchy to these things in, say, a typical blog index:

  • You're going to have one footer on a page.
  • You're going to have one header per entry.
  • You're going to have n paragraphs per entry.

Establish whitespace for your paragraphs knowing that they're going to sometimes occur in sequence -- you need to worry about how they look as a series. From there, adjust your headers to deal with boundaries between entries. Finally, adjust your footer/body spacing to make sure the bottom of the page looks decent.

It's a thumbnail sketch. How you ultimately end up assigning your padding is entirely up to you, but if you approach it from an bottom-up perspective you'll likely see less surprises as you tweak first the most common/plentiful elements and then later the less common ones.

Josh Millard
+4  A: 

If you want some space around an element, give it a margin. That means, in this case, don't just give the <h1> a bottom margin, but give <p> a top margin.

Remember, when two elements are vertically adjacent and they don't have a border or padding between them, their margins collapse. That means that only the larger of the two margins is considered - they don't add together. So this:

h1, p { margin: 1em; }

<h1>...</h1>
<p>...</p>

...would result in a 1em space between the heading and the paragraph.

Jim
+2  A: 

The point that Jim is making is the key. Margins collapse between elements, they are not additive. If what you want is to ensure that there is a 1em margin above and below paragraphs and headings and that there is a 1em margin below the header and above the footer, then your css should reflect that.

Given this markup (I've added a header and placed ids on the header/footer):

<body>
  <div id="header"></div>
  <h1>This is the heading</h1>
  <p>This is a paragraph</p>
  <h1>Here's another heading</h1>
  <div id="footer">This is a footer</div>
</body>

You should use this css:

#header {
  margin-bottom: 1em;
}

#footer {
  margin-top: 1em;
}

h1, p {
  margin: 1em 0;
}

Now the order of your elements doesn't matter. If you use two consecutive headings, or start the page with a paragraph instead of a heading it will still render the way that you indended.

Prestaul
+1  A: 

Using advanced CSS 2 selectors, another solution would be possible that does not rely on a class last to introduce layout info into the HTML.

The solution uses the adjacent selectors. Unfortunately, MSIE 6 doesn't support it yet so reluctance to use it is understandable.

h1 {
    margin: 0 0 1em;
}

div, p, p + h1, div + h1 {
    margin: 1em 0 0;
}

This way, the first h1 won't have a top margin while any h1 that immediately follows a paragraph or a box has a top margin.

Konrad Rudolph
+1  A: 

I'm a relative newbie, but my own solution to the thing I think both you and I came up against (changing margins for one tag may sort out spacing in one part of a site, only to disturb a previously good spacing elsewhere?) is now to allocate an equal margin top and bottom for all tags. You might well want more space above and below an H1 than for an H3 or a p, but in general I think pages look good with equal spaces above and below any given piece of text, so this solution works well for me and meets your 'simple rule of thumb' spec too, hopefully!