42

Say you have this html:

<a href="#">
    This is underlined
    <span>
        This isn't.
    </span>
</a>

And this css:

a:hover {
    text-decoration: underline; /* I know, this is enabled by default. */
}

a:hover span {
    text-decoration: none !important;
}

Why does the a > span element still has an underline. I'm pretty sure you should actually have undone the decoration by using 'none'. I know that you can achieve the result I want by using this:

<a href="#">
    <span class="underlined">
        This is underlined
    </span>
    <span>
        This isn't.
    </span>
</a>

plus this css:

a:hover {
    text-decoration: none;
}

a:hover span.underlined {
    text-decoration: underline;
}

But... it just doesn't make sense to me why you can't unset the text-decoration of a child-element. So, why...?

Edit: Inline-blocks

According to @amosrivera, it does work when you use inline-block. I can confirm this to work in Safari and Chrome!

a:hover span{
    text-decoration:none;
    display:inline-block;
}

As mentioned, this works for Safari and Chrome, but not for Firefox. The following solution works for Firefox, but not for Safari and Chrome...

a:hover span{
    text-decoration:none;
    display:block;
}

Little table:

    CSS-Rule            |    Webkit    |    Firefox    |    Opera    |    IE    
--------------------------------------------------------------------------------
display: block;         |       x      |               |      ?      |     ?    
display: inline-block;  |              |       x       |      ?      |     ?
cutsoy
  • 10,127
  • 4
  • 40
  • 57
  • 1
    IE7, works without anything, IE8 and Opera both work with inline-block. FF3.6/4 is wrong, it explicitly says in the [text-decoration definition](http://www.w3.org/TR/CSS21/text.html#propdef-text-decoration) "_User agents must not render these text decorations on content that is not text. For example, images and inline blocks must not be underlined._" – clairesuzy Mar 25 '11 at 16:50

7 Answers7

39

It has to do with the fact that span is an inline element. Try this:

a span{
    text-decoration:none;
    display:inline-block;
}

Online demo: http://jsfiddle.net/yffXp/

UPDATE

In FF (4?) only display:block works (which at the same time in webkit doesn't), causes line break.

UPDATE 2 (hack?)

a span{
    display:inline-block;
    background:#fff;
    line-height:1.1em;
}

Overlaying the white background over the border is not pretty but it seems to do it. It works in every browser other than IE 6,7

Online demo: http://jsfiddle.net/yffXp/6/

amosrivera
  • 26,114
  • 9
  • 67
  • 76
  • That is interesting. Do you know why it being an inline element is a factor? – Moses Mar 25 '11 at 15:58
  • The online demo shows everything underlined for me (FF 4). If I set it to `display: block;` the underline is gone as expected. – Stephen Watkins Mar 25 '11 at 16:00
  • Not still underlined in Chrome 10. – Andrew Marshall Mar 25 '11 at 16:01
  • 1
    @steve you're right, it doesnt work on ff4, just with display:block – amosrivera Mar 25 '11 at 16:04
  • @Moses, good question. And why display:block doesn't work, while inline-block does work. Doesn't make sense to me either... – cutsoy Mar 25 '11 at 16:04
  • Edit: display:block doesn't work in Webkit, while it does work in Firefox. Inline-block doesn't work in Firefox, while it does work in Safari. – cutsoy Mar 25 '11 at 16:07
  • Well, this got me curious, although i did not find an explanation, i tried this hack (working ff and chrome) let me know: http://jsfiddle.net/yffXp/2/ – amosrivera Mar 25 '11 at 16:15
  • 1
    I should point out that inline elements cannot be parents of block elements. So having an anchor (implicitly inline) with a nested span (explicitly block) is against the spec. Apparently, though, nesting an inline-block inside an inline element is just fine. – Moses Mar 25 '11 at 16:46
  • 1
    span is by default inline **not block** "These elements define content to be inline (SPAN)" http://www.w3.org/TR/html401/struct/global.html – amosrivera Mar 25 '11 at 16:54
  • 1
    That last demo isn't really a solution. For example: http://jsfiddle.net/yffXp/8/ – thirtydot Mar 25 '11 at 16:55
  • 1
    @Moses you're quite right about nesting block level elements inside inline ones, but changing a CSS display not change the actual element properties so nesting a *inline* `span` with `display:block` inside an *inline* `a` is perfectly OK it will validate however you will then get the line breaks ;) – clairesuzy Mar 25 '11 at 16:56
  • @thirtydot yeah, thats why i stated "Overlaying the white background over the border is not pretty" ;) – amosrivera Mar 25 '11 at 17:00
  • Unfortunately it seems that if the parent is also `display: flex` the child will always get an underline regardless of its `display` property. – powerbuoy Jun 22 '16 at 10:39
14

There might be some incredibly zany cross-browser way to do it, but I'd just go with this (a variation of the solution in your question), for the sake of sanity:

It just works: http://jsfiddle.net/KrepM/1/

HTML:

<a href="#">
    <span>This is underlined</span>
    This isn't.
</a>

CSS:

a:hover {
    text-decoration: none
}

a:hover span {
    text-decoration: underline
}
thirtydot
  • 224,678
  • 48
  • 389
  • 349
2

As a solution, I'd use @thirtydot's one, but as far as the problem is concerned, I think you are looking at it the wrong way.

Check the following fiddle: As you can see the non-decorated part is not decorated with the colour given; what you are seeing is the colour of it´s parent that extends to the end of the element (as spaces in an a are underlined as well). So the browser is really doing what you are telling it to do, you just don´t see it.

As a reference, compare the previous fiddle with this one. And guess what happens when you change the colour of the span to the background colour...

jeroen
  • 91,079
  • 21
  • 114
  • 132
  • 1
    This is true, the underlining is propagating to the inline child element (anonymous or otherwise), like color does - but then the recs (there's a link in a comment to the OP) specifically state the handling of underlining on inline-blocks and images (it shouldn't propagate!) so I'd say that those browsers not handling the inline-block solution here are being naughty ;) – clairesuzy Mar 25 '11 at 17:19
1

Caught that problem when I used a class for my link.

<a href="#close" class="close">&times;</a>

If I used .close in my css chrome and safari kept underlining the link. When I added a tag before class name everything started working fine.

a {
    text-decoration: none;
}
a.close {
    color: black;
}
0

@amosrivera's answer helped me out but it wasn't enough:

I had the following:

<p>
    some text
</p>

Which was getting underlined from a distant ancestor element's <a> element. Even after directly selecting the <p> element and applying text-decoration: none, it still had underlines. So I had to do the following:

  1. Wrap all text in a span:
    <p>
        <span>some text</span>
    </p>
    
  2. Then I could use @amosrivera's answer:
    span {
        display: inline-block;
    }
    

I apparently don't even need text-decoration: none!

derpedy-doo
  • 1,097
  • 1
  • 18
  • 22
0

The text-decoration will propagate to all elements (similar to color) that are not display: block or inline-block (even flex/grid layouts are affected).

But there's a simple trick to undo text-decoration if it has certain nested elements using the has selector:

a:hover {
  text-decoration: underline;
}
a:hover:has(span) {
  text-decoration: none;
}

This will disable text-decoration for the parent if it has a certain child element.

Now I know this isn't exactly the scenario described above. For that specific case there's indeed no alternative than using block.

Johannes
  • 316
  • 3
  • 4
-1

I came across this problem today, but for pseudo elements, which amounts to the same situation and I was able to find a solution. Set overflow:hidden; on the child element. Then set your height of the child element slightly smaller than the height for the rest of the link. You'll have to play with the height a few times to get it just right, but eventually you should be able to make the underline disappear.

VirtuosiMedia
  • 52,016
  • 21
  • 93
  • 140