Tuesday, 9. Jan 2007

Replacing HR elements with images

Yesterday I was presented with the problem of using an image for the HR tag. Quick googling confirmed my suspicion, that this is something a lot of people want to achieve but apparently it can't be done because of, as usual, IE's limitations.

The recommendations seem to be to either wrap the HR in a div and styling that, or just simply work around it by not using images. But of course it can be done, and here's how:

We start with some nice clean code for all the alternative browsers:

hr {
  border : 0;
  height : 15px;
  background : url(hr.gif) 0 0 no-repeat;
  margin : 1em 0;
}

This seems to work for all standards compliant modern browsers. I've tested it on Opera, Safari & Firefox. However, it does not work on Explorer. IE treats the element as inline and demands a border around it and a minimum height of 1px.

IE supports very basic generated content with the list-style-image setting when combined with display: list-item. This is what I've used to get around the limitations.

Add this into conditional comments (or hacks if you prefer) to shift the element out of the way and insert a bullet picture in the resulting space:

hr {
  display : list-item;
  list-style : url(hr.gif) inside;
  filter : alpha(opacity=0);
  width : 0;
}

My implementation here has the limitation of demanding that the image you use is equal to the width of the text area, but this should be easy to get around or customize.

The border setting can be replaced with a color: #fff;. To kill the default border you must set either one to the background color. Possibly it might be shifted out of hidden overflow but I have not tried it.

You can view a live example here.

Updated - 16. 1. 2007:

I've updated this entry and the example with the improvements suggested by Már. There are no longer any limitations on this technique.

11 comments to “Replacing HR elements with images”

  1. TÖFFARI

    Krilli wrote 13.1.2007 0:06

  2. Here's my tweak with changes highlighted with bold:

    hr {
      border : 0;
      height : 15px;
      background : url(hr.gif) 50% 0 no-repeat;
      margin : 1em 0;
    }
    
    /* --- IE hack --- */
    * HTML hr,
    *:first-child+html hr {
      display : list-item;
      list-style-image : url(hr.gif);
      list-style-position : inside;
      border : 1px solid #fff;
      width : 0;
      height : 0;
      margin-bottom : .5em;
    }
    /* --- end hack --- */

    Notes:

    list-style-position : inside; (combined with the appropriate text-align and margin-left settings) allows you to use images of any sizes and align them however you want.
    height : 0; reduces the footprint of the white border down to a single pixel.
    margin-bottom : .5em; makes the bottom margin of the HR the same in IE and Firefox. YMMV.

    Már wrote 13.1.2007 3:13

  3. P.S. Also worth noting, I dropped the rule text-align : right; to allow the center-alignment (default in IE) to kick in.

    Már wrote 13.1.2007 3:17

  4. P.P.S. I've only tested this on IE7, so some tweaks might be in order for IE5 - IE6.

    Már wrote 13.1.2007 3:24

  5. Yes! Of course! list-style-position is the key. How could I have missed that? I'd done some tests to get it to center (which is what I really wanted) but gave up on it. I might add your improvements to the example at least. :-)

    I know for a fact that this does not work (to my great annoyance):

    * HTML hr,
    *:first-child+HTML hr {
    /* rules */
    }

    IE6 doesn't understand the second selector and skips the block entirely. It has to be broken up into two identical hacks (which I have done for the one web that I've used this for) or conditional comment.

    Borgar wrote 13.1.2007 13:11

  6. Stupid, stupid IE. Grrr!

    Well, then there's always the option of doing it all inline the ordinary selector block, using the nonsensial property : expression("value"); pattern - like so:

     /* IE hack */
      display : expression("list-item");
      list-style : expression("url(hr.gif) inside");
      border : expression("1px solid #fff");
      width : expression("0");
      height : expression"0");
      margin-bottom : expression(".5em");
     /* End hack */

    TIMTOWTDI!

    Már wrote 13.1.2007 23:02

  7. When I think about it, this last idea is actually quite terrible - beacuse it also implicitly targets all future versions of IE (curse them).

    P.S. Borgar, you should really disable your evil auto-acronymizer macro, for text inside <pre> blocks and <code> spans.

    Már wrote 13.1.2007 23:07

  8. Actually, replace the border rule with filter : alpha(opacity=0); and the border disappears completely!

    You may now also remove the height : 0; rule, and use only the margin-bottom rule to keep the bottom-margin rendering consistent between browsers.

    Már wrote 13.1.2007 23:28

  9. Thanks guys (thuys).

    If this were the Demo Screne then I might be tempted to say that we horizontal rule! *ahem*.

    I've updated the entry and example to the best case (Már's improvements) in case someone stumbles across this later and doesn't bother reading the comments.

    And yes, that acronymizer really needs to cool it. In my defense I can only say that it's someone else's code. :-)

    Borgar wrote 16.1.2007 9:45

  10. Hey you tow, I love your solution! it works fine with me. Tested on Safari and Firfox (mac) AND IE 6 (PC). Thank you! See the border @ HTTP://www.the-lighthouse-keepers-cat.com/wp_en-EN/ (^-^)

    sissT wrote 2.5.2007 2:53

  11. Lovely solution, and a nice flourish graphic too...do you mind if I use not only the code but the graphic too?

    Darryl wrote 8.5.2007 6:26


This page

Archives

Search this page


Page style: Use my settings