Equal margins between HTML elements, done properly

November 10th, 2009 § 3

As a front end developer one of the things I’m always interested in is improving my code. To make it cleaner, smaller, more efficient. Some developers feel satisfied by putting out code as fast as they humanly can.

For the most part that works, but every now and then you receive a project that will eventually grow beyond it’s original scope. And if your code isn’t clean and planned out from the beginning, maintaining it will be nothing short of a nightmare. And what could be a simple mundane task can turn into a world of hurt.

Let’s see how you can apply equal margins between any number of HTML elements with just a couple of CSS selectors.

I’m going to start off with a simple 2 column layout.

propermargins1We have a simple structure: a main wrapper, and 3 main elements that we want to separate from each other with equal margins. How would I do this a few months ago?

I’d jump right to the main wrapper, give it a padding of (let’s say) 8 pixels all around, and then apply margins from the top element of the design to the bottom one.

Now I’d jump to the first element, and give it a margin-bottom of 8 pixels once again, and then I’d apply the final margin to element 2 or 3, on the right or left side, respectively.

propermargins2

You’re probably thinking by now “This is all fine and normal, why and how could we improve upon this?

This probably doesn’t seem like much of a problem when you’re working with a very simple layout. But remember that every time you decide to put another element, like for example, a footer in this layout, you’d have to put another margin definition, if you put in a third column, yet another margin definition. See where we’re getting with this?

So what would start off as 3 rules would eventually grow into a behemoth of them. Now let’s suppose you have a more complex layout, like you usually do in real case scenarios. Actually no, let’s go extreme, imagine you used this method to style a site with a layout as complex as New York Time’s. You spend months developing it internally, testing, and making sure everything works and displays properly in every browser.

A year or two have gone by, and the web team decides to revise the design. And one of the things they decide is:

“Let’s squeeze/increase the margin between elements so we can fit/remove a column.”

This is the part where the front end developers start tearing off their hair. I certainly would, and similar things have happened to me before. Thankfully, the complexity of those designs was nowhere close to the NY Times’.

So what’s the proper solution? This:

propermargins3So you’re looking at the picture and wondering, how you can turn that into simple rules. Supposing we’re considering CSS 2.1 support, which all modern browsers support, you’d simply do this:

#mainwrapper { padding: 4px; }
#mainwrapper > div { margin: 4px }

That’s it. No matter how many more columns or elements you add to the main structure of the design, those rules will properly separate all of them.

Note: for those that don’t know, the second selector with the “>” selects all the divs that are immediately preceded by #mainwrapper. In other words, it only works for the children of #mainwrapper, not for the grand children, nor great grand children, only the elements that interest us.

The only thing you need to do is to keep their widths in check. And please, if you’ve learned anything from this, don’t apply the same value of widths for all of those,  do something like:

.slimcolumn { width: 100px }

And apply that to all the divs that require it.

This technique isn’t limited to main structures of templates, it can be applied to anything. Menus, modules inside columns. Whatever it is that you need to do that requires equal spacing between elements can be done using a technique similar to this.

Some might argue that you could have used PHP to do a mass replacement of margin values in specific elements, but that doesn’t make the code any smaller, more efficient and cleaner. Doesn’t make it easier to maintain in case you change the structure either.

Hold it mister, what about Internet Explorer 6? Are you putting it aside like all the others, claiming it’s dead and is of no concern to us?

No, of course not. The point of this article isn’t to discuss browser compatibility.

However, the technique used here can be adapted to work on IE6, for that you’d need to reduce the margin value to half for floated elements on an IE6 specific CSS file, or try one of the many fixes for this particular bug. Personally, I prefer IE6-specific CSS and it’s easier to maintain and to remember what definitions were made specifically for it.

#mainwrapper div { margin: 4px }
#mainwrapper #2, #mainwrapper #3 { margin: 2px }
#mainwrapper div div { margin: 0; }

(I know you can’t use numbers at the start of IDs, this is only an example)

Yes, you’d have to add every floated field to this definition. This definition controls and fixes the margin issue for all of them. But isn’t this X times better than having a rendering issue spread out throughout X layout elements, and having to fix them one by one? (where X is the number of floated elements in your design)

If you keep your code efficient and well organized, not only will it make your job easier, you’ll thank yourself for it later on in case you, or anyone else, has to return to the project and build something upon it.

Limitations with IE6/7

Shortly after I posted my article Stephanie Sullivan pointed out that I would have a problem with my method with margin collapse and she’s right. Right now this method will only work for elements that are floated on opposite directions, or not floated at all.

I will write another article in the near future to try to address this issue. It will probably take more than a couple of CSS lines though. Stay tuned for the next part!

If you’d like to use this technique *NOW* and be compatible with IE6/7, I recommend you use padding instead of margin, and nest another div inside of each. Ideally I’d like to avoid using unnecessary divs, but in order to support old browsers it’s a decent quick solution.

Credit where it’s due

I could have never thought of this technique unless I had witnessed and studied Nicole Sullivan’s Object Oriented CSS. She made me think about not only what I was coding, but how efficient or maintainable it was, and this technique is a reflection of what she taught me, nothing more.

Now let me run away before she nags me for using IDs instead of classes :)

§ 3 Responses to “Equal margins between HTML elements, done properly”

  • Xavier Barbosa says:

    This kind of layout is very common so its always good to improve on its implementation. Thanks for sharing!

  • I was *so* going to nag you about the IDs. :D

    This article describes the problem which made me decide not to include gutters on my grids and template. Preferring to handle the spacing on the content elements or a nested div inside left col.

    Do you really need padding on mainwrapper? Could you set it to be slightly narrower?

    Nice article, thanks for coming to my talk!

    Cheers,
    Nicole

  • Griffith says:

    Hi Nicole, thank you for coming to my humble blog :)

    If you don’t put padding on the mainwrapper you won’t achieve equal margins between all the elements. The alternative to not using mainwrapper would be to manually change the margins of the elements on the edges.

    Example:

    #1 { margin-top: 8px }
    #2 { margin-left: 8px }
    #3 { margin-right: 8px }
    #2, 3 { margin-bottom: 8px }

    While that definitely works, it’s definitely less practical the more complex your layout becomes.

  • § Leave a Reply

What's this?

You are currently reading Equal margins between HTML elements, done properly at The Whitehawk.

meta