Blog Improve It

Margins on the HR tag: a case solved

Posted by Leandro Mello about 1 year 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  | 3 comments

The common denominator

Posted by Leandro Mello about 1 year ago.

On the web, even if you can't show an image, you can still speak the thousand words.

Last Friday I discovered a detail in my method of writing CSS that I intend to adopt as "best practice" for me in every project from now on: the only style sheet which, in a project that includes screen/printing/mobile, should have attribute media="all". I call it "typography.css".

Inspiration come from out of the web

I came up with this method by applying, in web design, some of the modus operandi used by advertisers and designers off-web.

In design and advertising, people are used to dealing separately with layout and typography. That's because design applied to text has itself such a strong personality, that it deserves special attention. There are lots of companies which devote themselves to typography only, and spend days, even weeks, to give birth to a single, complete, beautiful font. The looks of the text hold their very own power.

On the web, we suffer from serious constraints regarding typography. It's impossible to use unique typefaces in a website because they may not exist in the user's computer. Using fancy images for text implies some risks to accessibility, and embedding one's own set of fonts in the code has issues of its own. In a nutshell, patience: we'll just use the cards we're given and know how to play with them. Which is fine, since this article isn't really about typography itself, but what we can learn from the habit of putting it apart from the layout.

Consistency and visual identity

The good thing about CSS is that it ensures consistency throughout one's site pages. One little change in a single selector and voilà, thousands os pages updated at once! That's all about what we call visual identity.

A company that respects its own visual identity demands that, at least, its corporate typography be consistent in every communication medium, whether print or electronic, and as much as possible. Layout schemes may be subject to little adjustments every now and then, because of the diversity of surfaces they can be applied to, but the way text looks must respect an even more global, thorough consistency across media — the designer might one day find him or herself having to make a piece of design that relies solely on typography, and people have to be able to realize just which company such piece belongs to. On the web, relying heavily on text is something that happens quite often.

The common denominator

Imagine your site is whole: printable, mobile-friendly, presentation-ready, almighty. Now strip off all the fancy stuff. Images, layout luxuries and everything. What's left? Text. On the web, even if you can't show an image, you can still speak the thousand words. And can as well spread them to other media. So, why not creating a style sheet that deals only with what regards text?

How it happened to me

As the projects I've been working with were growing, it got more and more complicated to browse through the sea of selectors. Since I write CSS in an incredibly regular fashion, with every property always obeying the same pattern and order (ok, call me maniac), I realized text properties came always grouped before layout properties. To decrease file size, I decided to throw all those text properties on a separate file, which I called typography.css.

So, for an example:

.rss_links a, 
.podcast_files h4 a {
    font-size:              80%;
    text-transform:         uppercase;
    text-decoration:        none;
    padding:                .3em 1em;
    background:             #F7F7F7 url(/images/background/gradient_light_to_dark.png) repeat-x bottom left;
    border:                 1px outset #F7F7F7;
}

... was split in a part that went to typography.css:

.rss_links a, 
.podcast_files h4 a {
    font-size:              80%;
    text-transform:         uppercase;
    text-decoration:        none;
}

... and another one that remained in the original application.css:

.rss_links a, 
.podcast_files h4 a {
    padding:                .3em 1em;
    background:             #F7F7F7 url(/images/background/gradient_light_to_dark.png) repeat-x bottom left;
    border:                 1px outset #F7F7F7;
}

And so on, with all of the selectors. The splitting was quite easy. The decision of making the split and the name of the new style sheet was more due to my old habits as a graphic designer — and a slight hope that it actually decreased file size — than to having any idea of what it would result in (I barely knew, but there would be pretty interesting results).

There is a moment when it's time to make a print and a mobile CSS. On my first experiments since I began using the "typography" method, I decided applying the same principle to the print and handheld media, thus creating style sheets called application_print and typography_print, and application_handheld and typography_handheld.

My "stylesheets" folder then became like this:

Beautiful! But, boy... six style sheets just because I was all into this putting-typography-apart-from-layout designer fuss? "There has to be a better way to do this", I thought. And there was. With the subtle perception that typography (as said a little before) must be global.

Refactoring, results and advantages

I came to realize that the selectors on all of the typography files were very alike. So I mixed up typography, typography_handheld and typography_print into a single typography.css. End of duplication: it would now take care by himself of everything text-related — font size, typeface colors, italics, bolds, capitals and so on. On the print CSS, since people usually prefer printing text in black, I just wrote html * { color: #000; } to make sure everything got black (and made the same to some stubborn selectors that were left).

After all that, in the HTML head, I gave typography.css the exclusive attribute media="all". Other style sheets should concern their own specific media. Thus, all these sheets would inherit the same text properties, which would in turn ensure consistency not only among every page in a website, but across the many media available by a given company and its website. All about visual identity, fellow reader!

This method brought up some other advantages:

The new practice has been bringing me good results. Sure, there are exceptions: in a small project one doesn't intend to print or see in a handheld device, it's just not worth separating typography and layout. On the other hand, a huge project, even one that may have a typography.css, has more chances of having additional style sheets which would probably discredit my "n+1" count. But all in all, working my CSS out is a lot easier when I take care of one thing at a time. That's something I'm going to adopt as best practice on my future projects, that's for sure... until better practices come up! :)

This was my first entry on Improve It's blog. I hope the information shown here has been useful somehow, and inspire designers and programmers some good practices. Up to what I've experienced, this method was one to really make work easier here. Sure, either I haven't read enough about CSS, or this topic about separating typography is already old history around the world, or both of them. That's why I invite you designer fellows to join the discussion (and to aid me with my rusty english!). Who knows how much improved this methodology (and my english skills) can get? :)

Tags  | 1 comment