Blog Improve It

Margins on the HR tag: a case solved

Posted by Leandro Mello over 5 years ago.

Basically, the smack on the head that makes IE behave is display: block. After that, you can play with whichever margins you want on <hr />.

I am one of those who use the <hr /> tag to split sections. It’s semantically more coherent than dividing by styling the very divs’ borders, it looks better when you view the HTML without CSS, and all that stuff that’s been discussed a lot all around. I came to appreciate <hr />’s usefulness.

The fact, however, is that it’s a pain to style this tag. For each browser different attributes must be edited in order to achieve the same effect. With some working, the <hr /> gets the same look in every browser.

What really makes people all over forums pull their hair out is the damn margin that surrounds the <hr /> in IE. IE’s margin is stubborn, indestructible, uncontrollable, unstylable. Wherever I looked for, people gave in to adopting the margins, and more persistent designers even encased the <hr /> into a <div> to get the desired style. In other words, some gave up too easily, some took desperate measures and wouldn’t care to make things right.

One day, I stumbled upon two blog articles which came near to a solution. Neither of them solved the case by itself. But joining both, it worked! Tests confirmed that by mixing both theories I could attain any margin size I wanted, in every browser — even zero. But, in a very unfortunate turn, I never bookmarked such articles, nor have I saved my test files. A very looked-for answer, lost in such a silly way...

This article is about my specific case: I wanted to use <hr /> free from any nonsense divs, and with zero margin — even in IE. And, above all things, this article is all about leaving the answer somewhere safe and under everyone’s reach. Now that I’ve remembered the solution, I won’t lose it again.

“Smack that head”

After I’d lost track of those articles and weeks had passed by, all I could remember was that Internet Explorer needed a smack in the head: a completely unexpected, counter-intuitive attribute that would get it back to its senses. Basically, the smack on the head that makes IE behave is display: block. After that, you can play with whichever margins you want on <hr />.

Who figures. The <hr /> element is already a block. In every way it looks like a block element. Breaks line above, breaks line below, there’s nothing inline on it. And that seems to be why so many forums chase their tails for a solution: few would suspect that it is necessary to remind <hr /> that it’s actually a block. Saying display: block would be plain redundant and unnecessary. But damned IEvil demands it in order to realize “oh well, what do you know, it’s true...”.

How it happened to me:

On with my case. I wanted to add some <hr /> tags to Brazilian photographer Patricia Figueira’s site, as an experiment for future execution on her own site, as well as on our currently under development product, beonthe.net.

First step was to insert those tags in the spaces between header, main content and footer. Let’s see the HTML:

<div id="header">
  (header content)
</div>
<hr />
<div id="main_content">
  (main content)
</div>
<hr />
<div id="footer">
  (footer content)
</div>

And came out the gray line between divs. Like this:

Safari: Hr was added correctly.

Opera: Hr added correctly as well.

Firefox: Hr added correctly, just like the others.

Internet Explorer 7: Hr was added correctly, but had margins that pushed away the divs’ content.

Internet Explorer 6: Hr was added correctly, but also had the margins that pushed away the divs’ content.

(Boy, that’s IE...)

Once inserted, I wanted each divider line to have the following features:

First task is simple. In our style sheet application.css, we write:

hr {
  clear:      both;
}

Now comes the second task: cleaning the spaces the line generates on IE. But as said before and so many times on blogs all around, <hr />’s margin on IE is persistent, ruthless, stainless, shameless. People around have tried everything: margin: 0, padding: 0, line-height: 0, font-size: 0, even overflow: hidden. Going margin zero works with standard-compliant browsers, but nothing beats those gaps on IE.

So, in our application.css, let’s guarantee there’s no margin on the smart browsers:

hr {
  clear:      both;
  margin:     0;
}

The explanation for IE’s insistent margins is that IE renders the <hr /> tag with a vertical margin 7px longer than other browsers. In other words, if you write...

hr {
  clear:      both;
  margin:     7px 0;
}

... You get, in a decent browser, the expected: Exactly 7px up and 7px down.

And on IE, a sum of what you wrote plus its native margins: 14px up and 14px down (7 + 7).

“So”, I might think, “I just have to write negative margins for IE”. Would be the intuitive thing to do, but IE isn’t all about intuitiveness. It won’t work: the upper margins goes away, but the lower one never gives in! Check it out: The hr tag gets upper space = zero, but the lower space doubles: it takes the upper space’s 7px for itself!

The ace in the hole

Enter in our application.css the attribute display: block:

hr {
  clear:      both;
  margin:     0;
  display:    block;
}

This is the last attribute I’d think about to eliminate margins. I can’t explain why it works. It’s counter-intuitive. It’s redundant. It’s idiot. And nevertheless (or perhaps just because of this) it makes IE wake up.

Now we can think about that negative margin subject. Then we just correct application.css:

hr {
  clear:      both;
  margin:     -7px 0;
  display:    block;
}

And voilà! Finally, an <hr /> tag with no margins! Not an illusion! It IS possible to totally eliminate an hr’s margins on IE!

Conditional comment:

Problem with using negative margins is that standard-compliant browsers interpret them just as they are — negative: Negative margins on Safari.

We have to set a behavior for each type of browser.

I’m used to using conditional comments. Some say they are bad, but so far they have but helped me a lot.

On to the <head> on HTML. There we insert a condition for IE:

<!--[if IE]>
  <link href="/stylesheets/application_ie.css" media="all" rel="stylesheet" type="text/css" />
<![endif]-->

It’s purpose is to call a style sheet with rules exclusively for Internet Explorer: application_ie.css.

In this new application_ie.css style sheet, we apply the negative margins we had up to now:

hr {
  margin:     -7px 0;
}

There you are. This is the only rule that distinguishes the <hr /> tag on smart browsers and on Internet Explorer. Now we can go back to application.css and make our margins go zero:

hr {
  clear:      both;
  margin:     0;
  display:    block;
}

And the result is: consensus! On the smart browsers: (Appearance of hr on Safari. It&rsquos the same as on IE!)

... and on IE: (Appearance of hr on IE6. Now every browser’s hr has got the same look.)

Finishing touches

Only the third task’s left, which is to make those lines invisible. This is easy with visibility: hidden:

hr {
  clear:      both;
  margin:     0;
  display:    block;
  visibility: hidden;
}

Which renders the <hr /> invisible, but still taking the room it has been taking before, in a way there’s a 2 pixel gap between the header and the main content: The hr is now gone, but there is still a gap where the hr was before. We have to get rid of it.

Note: Using display: none is useless in this case, because it cancels the clear: both attribute. And we want it to break the floats. In this case, better stick with visibility: hidden.

On the decent browsers, this gap is due to border width. 1px borders around a zero height element result in a 2px total height. A border attribute should do it:

hr {
  clear:      both;
  margin:     0;
  display:    block;
  visibility: hidden;
  border:     none;
}

The gap is now gone on Safari and Opera. But Firefox and IE need a little further push. Remind them the element’s height must be null:

hr {
  clear:      both;
  margin:     0;
  display:    block;
  visibility: hidden;
  border:     none;
  height:     0;
}

Firefox now is okay. But on IE, the gap, instead of disappearing, got reduced to 1px (boy, that’s IE...). That’s because on IE’s <hr /> the borders aren’t defined by the border, but instead by the color (have I mentioned IE isn’t all about intuitiveness?). As one’s color can’t just go “zero” to make the gap go, the way left is to tweak the margins we have on application_ie.css, adding 1px above or below:

hr {
  margin:     -8px 0 -7px 0;
}

And there you have the final result: On all browsers, an invisible divider line with no margins. Mission complete.

Conclusion

This was my very specific case involving the <hr /> tag. If you are one of those people who pulled your hair out because of IE’s stubborn margins, know that there’s a solution. You don’t need to adapt you precious layout to fit the margins, nor you have to enclose the tag within a <div> only for it. Best practices, now!

I hope I have helped relieve your pain in the neck. Now the answer is right here, for the whole world. Soon you’ll see it in action at Patricia Figueira’s site and at beonthe.net. But if this article doesn’t solve your particular case, write me. Let’s think together of solutions for taming <hr /> — and maybe, just maybe, Internet Explorer itself.

Tags  | 11 comments

How did you like it? Write your comments and suggestions below!

Follow up this page’s RSS.

Comments (11 up to now)

  1. vm123 said 3 months later:

    This works! Thanks so much..

  2. Anthony said 10 months later:

    You deserve a medal.

  3. ComfotablyNumb said about 1 year later:

    Excellent tut. Just what I needed!!!

    Cheers...

  4. Xiao Z. Jia said about 1 year later:

    Thanks a bunch, I need to get my own notebook of solutions, since I'm constantly solving problems and forgetting how I solved them lol.

  5. Shannon T said about 1 year later:

    YES YES YES, thank you this worked!

  6. Rob said over 2 years later:

    Merci

  7. Heinz Traub said over 2 years later:

    Don't ask me why nor how it works but this is what worked for me in IE 8 and with no conditional comments:

    hr.HeinzDashedLine { display: block; vertical-align: top; margin: 0px; /* Not needed but just in case */ padding: 0px; /* Not needed but just in case */ height: 1px; border-bottom: 1px dashed #d2d2d2; }

  8. Arkana said over 3 years later:

    Thanks! This tutorial is very useful. Can I translate it for my (future) blog? Of course, mentioning you as the source.

    (I love the "boy, that's IE" comments, and that stuff, I think i'll keep them :D)

  9. Steve said over 4 years later:

    This is a GREAT article, and gave me some awesome pointers. However, I'm still stuck with an annoying visual artifact on my


    . In FF-15 it looks perfect; in IE9 and Chrome 24 it seems to have this little "hook" on the left side of the
    . It almost looks like it's trying to be a really thin input box rather than a
    And believe it or not, it looks worse in Chrome than it does in IE. FWIW, the consultant who built the site (using a WYSIWYG, darnit) set the DTD to XHTML 1.1. Thoughts?

  10. Glad said over 4 years later:

    Awesome! Saved me a lot of time, sweat, and blood! haha! :D

  11. SS said over 4 years later:

    Saved me some serious frustration as I struggled to investigate what's adding the margin on IE when it is working perfectly on Firefox.

    Thanks for taking the time and effort in sharing this.