7

I want to apply a line-through to the contents of <td> tags except for the <a> tag within a tag. The styles I am applying do not seem to work though... any ideas?

Here's the example to play with (I'm testing in IE8): http://jsfiddle.net/9qbsq/

Here's what the markup looks like...

HTML

<table border=1>
  <tr class="highlight">
      <td>hello</td>
      <td><a href="#">world</a></td>
  </tr>
  <tr>
      <td>foo</td>
      <td>bar</td>
  </tr>
</table>

CSS

.highlight td { text-decoration:line-through; }
.highlight td a { text-decoration:none; }
Coderama
  • 11,050
  • 12
  • 44
  • 58

4 Answers4

5

The problem is that text-decoration propagates to descendants:

When specified on or propagated to an inline element, it affects all the boxes generated by that element, and is further propagated to any in-flow block-level boxes that split the inline [...]

For block containers that establish an inline formatting context, the decorations are propagated to an anonymous inline element that wraps all the in-flow inline-level children of the block container.

For all other elements it is propagated to any in-flow children.

But there are two exceptions: out-of-flow and atomic inline-level descendants:

Note that text decorations are not propagated to floating and absolutely positioned descendants, nor to the contents of atomic inline-level descendants such as inline blocks and inline tables.

Therefore, you can use display: inline-block on a child to prevent its parent's text-decoration from affecting it.

.highlight > td {
  text-decoration: line-through;
}
.highlight > td > a {
  display: inline-block; /* Remove parent's text-decoration */
  text-decoration: none; /* Remove default link underline */
}
<table border=1>
  <tr class="highlight">
    <td>hello</td>
    <td><a href="#">world</a></td>
  </tr>
  <tr>
    <td>foo</td>
    <td>bar</td>
  </tr>
</table>
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • `text-decoration: none` is not necessery, because `display: inline-block` already removes it – Alexander Malakhov Mar 31 '18 at 16:52
  • 1
    @AlexanderMalakhov `display: inline-block` removes underline propagated from ancestor, but does not avoid self underline assigned in UA stylesheet. – Oriol Apr 02 '18 at 18:04
  • This worked for me, but I couldn't use it on a `button` element. It did work when I targeted a `p` element inside the button. Does anyone know why that worked? – Frozenfrank Jan 31 '23 at 19:49
5

That's how it should work - whilst the a element does have text-decoration: none, the line through is still being set.

You could add a span in each td as a workaround, and set the text-decoration: line-through on that span if required.

alex
  • 479,566
  • 201
  • 878
  • 984
  • 3
    +1 Why this is the case, well, because the spec says so. See [this answer](http://stackoverflow.com/questions/4481318/css-text-decoration-property-cannot-be-overridden-by-ancestor-element/4481356#4481356). – BoltClock Jul 04 '11 at 01:59
4

You'll have to wrap the text in something like a span, and apply text-decoration: line-through to that: http://jsfiddle.net/9qbsq/1/

That way, you don't have to achieve the impossible task of removing line-through on a child element when a parent element has line-through applied.

thirtydot
  • 224,678
  • 48
  • 389
  • 349
  • 3
    Good answer. The Sitepoint `text-decoration` [reference page](http://reference.sitepoint.com/css/text-decoration) describes this behaviour: "Any text decoration setting on a descendant box can never 'undo' the text decorations of an ancestor box." – JT. Jul 04 '11 at 02:03
  • 1
    Better answer here: http://stackoverflow.com/a/19529256/1977420. Change the item's display to `inline-block` to clear out its `text-decoration`. – mikegertrudes Oct 22 '13 at 22:12
  • Better in most cases, for sure. It does have the downside of having to set the element to inline-block which might be bad if you need text to wrap, here's a contrived example: http://jsfiddle.net/thirtydot/9qbsq/19/ – thirtydot Oct 23 '13 at 14:19
2

This issue can easily be solved with the :not attribute.

HTML

<table border=1>
  <tr class="highlight">
      <td>hello</td>
      <td class='nostrike'><a href="#">world</a></td>
  </tr>
  <tr>
      <td>foo</td>
      <td>bar</td>
  </tr>
</table>

CSS

.highlight td:not(.nostrike) { text-decoration:line-through; }

This is usually cleaner when you want everything to have the strike except certain elements. Instead of adding a span to each with the strike, you can add filter it out when necessary.

richsoni
  • 4,188
  • 8
  • 34
  • 47