JeffCroft.com

Blog entry // 10.11.2005 // 10:57 AM // 34 Comments

Dotted-underline links that (mostly) work all over

Over the weekend, I was presented with a CSS issue that has driven me nuts ever since. It’s a small thing — this article isn’t going to change your life — and the solution I’ve come up with still has at least one bug that I’m hoping someone out there can help me fix. In any case…

A popular alternative to the traditional underlined links is to use a one pixel dotted border under the link. I’m sure you’ve all seen it. It’s a nice effect — a way to give your links a bit of unique style, but also keep them mostly in line with the usability recommendation that links be underlined for findability.

The issue that presented itself is this: when you use a border on a link, that border also gets applied to any linked images you have — which is usually not desirable. Here’s an example of this taking place. Note that the picture of Haley also gets the dotted bottom border (it’s subtle, but it’s there).

An aside: Every person that I have presented with this problem has had the same initial reaction I did: “Can’t you just do a img { border: none; }?” The answer is no, you can’t. The border is being applied to the anchor element, not the image. CSS doesn’t give us a way to select a parent element, so it’s impossible to say, “give me all links that contain images.” You could walk the DOM with Javascript and apply a class to each image that met this case, but that seems like overkill.

The reason this occurs is that borders come outside the box model, whereas the traditional text underline display inside the box. Because the image fills the box, you never see the text underline — but you do see the border. The key to finding a solution was to somehow get the dotted border inside the box. The almost-too-simple-to-write-about solution I came up with? Use a background image.

By creating a small, two-pixel tall background image and letting it repeat horizontally, you can achieve the dotted underline effect on text links, but not on images contained in links. In reality, the dotted background image is still there, but it’s hidden behind the image, so you never see it.

There’s a side-benefit, as well. Internet Explorer doesn’t support dotted borders (choosing to display them as the much-uglier “dashed,” instead). Using a background image, we can achieve the dotted effect in IE.

Here’s an example of the whole thing in action.

There’s always a “but”…

Remember I said there was still a sneaky little bug that I’m hoping you’ll help me solve? Yeah, well here it is: When a link wraps from one line to the next, Internet Explorer, for some completely inexplicable reason, chooses to display the background image only on the bottom-most line of text. It’s effectively treating the link as a sort-of block element, rather than an inline element like it should be. Two work-arounds (but definitely not solutions) to this issue might be:

  1. Just pass IE standard underlines and forget about it. IE sucks, anyway.
  2. Make your background image the same height as your text’s line-height and let it repeat vertically as well as horizontally. This would work, but would break text resizing and would require a different image for each different size of text you might have. Lame.

Anyone have a better idea for how to work around IE’s utter imcompetence?

Update

Thanks to Sean Sperte, who came up with an even better method of dealing with this problem. Sean uses a img { margin-bottom: -1px; vertical-align: sub; border: none; }, and it seems to work great in all significant browsers. Sean’s example is here. Two notes on this method:

  1. IE will still display dashed borders instead of dotted. if you need dotted in IE, then you’ll need to use the background image trick (and it’s associated bug).
  2. Because this method moves the images contained in links down by one pixel, you may need to compensate for this elsewhere in your design if you are going for an extremely precise layout.

Comments

  1. 001 // Ryan Brill // 10.11.2005 // 12:03 PM

    In Firefox, I still see the dotted line, albiet it is closer to the image and thus harder to see. However, it is still there.

  2. 002 // Nick // 10.11.2005 // 12:06 PM

    Combine your two ideas and make it background-repeat on IE only. IE doesn’t support text resizing (of pixel sized fonts) anyway, so the only thing you are losing out on now is underlines on different sized text. As long as the background position is still bottom left, this shouldn’t even matter unless those large links also span two lines, right?

  3. 003 // Jeff Croft // 10.11.2005 // 12:09 PM

    Ryan-

    I think you caught me in the middle of messing with it. It should be fine now.

  4. 004 // Jeff Croft // 10.11.2005 // 12:12 PM

    Nick-

    That’s a good point. Since IE doesn’t support pixel-sized font resizing anyway, you’re not losing much. But, in the examples (and most of my real-world work, too), I use ems for font sizes so they can be resized in IE. Hmm.

    And, no, it wouldn’t matter if the larger sized links spanned two lines or not. If I have a dotted line every, say, 11 pixels, then on 36 pixel-tall text you’re going to see three dotted lines.

  5. 005 // Ryan Brill // 10.11.2005 // 12:31 PM

    Jeff - Yep, it looks better now.

  6. 006 // Jim // 10.11.2005 // 12:40 PM

    How about forgetting the background trick, use normal underline, and use position: relative to position the image a few pixels lower down, covering up the underline?

  7. 007 // Jeff Croft // 10.11.2005 // 12:45 PM

    Jim-

    Forgetting the background trick and using normal underline” sort of defeats the purpose — the whole point of this is that the person I was doing this for wanted dotted underlines, not normal underlines. Also, normal underlines don’t show up under the image, so there’s no need to move the image if you’re using normal underlines.

    Using position: relative to move the image slighty to cover a dotted border would probably be suitable in some cases, but it wouldn’t be in all cases. What if I don’t want my image a couple pixels lower?! :)

  8. 008 // Sean Sperte // 10.11.2005 // 12:46 PM

    Jeff,

    Thanks for tackling this issue; it’s been a back-burner problem for me for a long time. Your post got me thinking and I think I’ve got a solution that’s even better than the background image:

    a img { margin-bottom: -1px; vertical-align: sub; border: none; }

    Works in Safari 2 and IE6 so far. I’m sure FireFox and others work well too. See for yourself.

  9. 009 // Sean Sperte // 10.11.2005 // 12:47 PM

    (Jim beat me to the punch, I guess) :)

  10. 010 // Jeff Croft // 10.11.2005 // 1:04 PM

    Hmm, Sean…that does seem to work. Sweet!

  11. 011 // Tony Summerville // 10.11.2005 // 1:33 PM

    Jeff -

    I ran into this problem a couple of months back and came up with a JavaScript solution. I use the DOM to find all links that have an img tag and apply a class to them. Then I turn off the border-bottom in that class.

    Here’s a post about it.

  12. 012 // Jeff Croft // 10.11.2005 // 1:35 PM

    Tony-

    I also had that same thought when the problem came up for me, but I decided that walking the DOM just for this is probably a bit of overkill. Still, it definitely works. :)

  13. 013 // James Asher // 10.11.2005 // 2:28 PM

    Jeff, your daughter must be adopted, she doesn’t look goofy at all, unlike yourself. ;-)

  14. 014 // Brian Ford // 10.11.2005 // 3:17 PM

    I can certainly vouch for the fact that Jeff’s daughter isn’t adopted. However, as I think that Haley looks just like Jeff (and always has) one can only conclude that Jeff either makes for a goofy looking man, or a cute-as-a-button 10 year old girl.

  15. 015 // Allan Rojas // 10.11.2005 // 3:48 PM

    What I do in my site is put the anchored-images inside a div identified with some special ID, say “foo”, then use a selector that says all anchors inside “foo” have no border…
    Since I do this only for anchored-images, it’s not so heavy. And I do it also for entire sections, like for example, all anchors in my header have no border…
    Hope that helps…

  16. 016 // Jeff Croft // 10.11.2005 // 5:36 PM

    Allan-

    That method works fine, but it requires you to modify the HTML in order to do it. In some cases we are either unable or unwilling to add classes or IDs to our code.

  17. 017 // Chris Griffin // 10.12.2005 // 12:35 AM

    In Sean’s example I still see the dotted line under photo. I am using FireFox on WinXP.

  18. 018 // Jeff Croft // 10.12.2005 // 12:42 AM

    Chris-

    That’s strange. In Firefox/XP, Sean’s version works great for me. Not sure what to say.

  19. 019 // Veerle Pieters // 10.12.2005 // 2:35 AM

    Very timely, I have this nasty rollover border that drives me nuts… until now, it’s solved thanks to you and Sean Sperte. Thanks a million! You both make my day :-)

  20. 020 // Richard@Home // 10.12.2005 // 3:57 AM

    Anyone have a better idea for how to work around IE’s utter imcompetence?”

    a { white-space:nowrap; }

    (stops the hyperlink text from wrapping in the middle)

  21. 021 // Jeff Croft // 10.12.2005 // 8:54 AM

    Veerle: Glad to be of assistance. :)

    Richard: Thank for reminding me — I should have pointed that out myself. I had tried it, and it certainly does work. However, it’s not practical in all cases. Sometimes you need to allow links to wrap. But yes, it’s definitely an option in some cases.

  22. 022 // Ryan Berg // 10.12.2005 // 10:13 AM

    Maybe I’m missing an obvious condition here, but wouldn’t:

    a { border-bottom: #CCC 1px dotted; }

    a img { border-bottom: none; }


    Work?

  23. 023 // Ryan Berg // 10.12.2005 // 10:14 AM

    Okay, I missed an obvious commission. Next time I’ll make sure to read the grey box.

  24. 024 // Elliot Swan // 10.12.2005 // 10:15 AM

    I also still see the dotted line under the photo in Sean’s example (on FireFox/WinXP).

    For me when I see a dotted underline on a link, there’s a px of space inbetween the link/image and the border. So when you shift the image by 1px, it just moves it right up to the border. If you shift by 2, then it will work.

    Not sure why it would only do this for me and Chris though.

  25. 025 // Jeff Croft // 10.12.2005 // 12:47 PM

    Elliot-

    The vertical-align: sub that both Sean and I used in our examples should align the image with the baseline. That’s why we did that. I’m not sure why it’s not working for you, though.

  26. 026 // Tony Summerville // 10.12.2005 // 3:40 PM

    You have to look closely, but the dotted line is still there on Firefox/WinXP.

    Close Up

    You have to change margin-bottom to -2px.

  27. 027 // Tony Summerville // 10.12.2005 // 3:43 PM

    I linked to a zoomed in image in the previous comment, but the HTML was filtered out.

  28. 028 // Sean Sperte // 10.12.2005 // 7:23 PM

    Yeah, looks like FireFox/XP uses an additional pixel for underlines. I’ve changed my example to -2px for the bottom margin and the dotted underline no longer appears on FireFox/XP.

    This (as Jeff mentioned) will have to be compensated for in designs that require precise, pixel layout.

    I recommend assigning some sort of class to anchors containing images anyway, though (if possible), and styling that class directly.

  29. 029 // Elliot Swan // 10.12.2005 // 8:30 PM

    Yep, that fixed it over here.

  30. 030 // Nathan Smith // 11.04.2005 // 11:04 AM

    Jeff, prompted by this article, I decided to start using dotted underlines for acronym tags on my site. I figure, they’re always back-to-back, with no spaces between letters, so there’s no linebreak, etc. I know that’s totally missing the point you were making, but just wanted to say thanks for giving me the idea.

  31. 031 // blurb // 11.12.2005 // 11:04 PM

    Thanks for posting this. I’ve been trying to solve this for MONTHS.

  32. 032 // Roman // 11.21.2005 // 5:32 AM

    Anyone have a better idea for how to work around IE’s utter imcompetence?’

    a { white-space:nowrap; }

    Richard: what about line breaks in left menus, for example? This is what drives me nuts in my current project, anyone with some sort of solution out there please?

  33. 033 // Matt // 11.16.2008 // 4:48 PM

    The margin-bottom: -1px; thing is kids stuff.

    It doesn’t matter what you do though or what method you try to use, you’re still going to get some kind of unexpected behavior in one browser or another (probably IE). Even using this method when hovering over certain links in IE the margin under the link will increase and decrease as you hover/unhover over the link on my sidebar. It’s stupid and I can’t figure out why.

  34. 034 // Sven // 01.08.2009 // 5:08 AM

    what about setting the dotted underline only on a tags inside of p elements..

    as far as i remember i never had placed linked images into p tags..

    so in this case every a outside of p doesnt get the border.

    stop me if got stuck in my mind..

Tags for this entry
Links in this entry