Search code examples
javascripthtmlcss

confused by CSS precedence


I have 2 css rule sets applying to a cell of a table. I thought one set of rules would override the other, but it is picking and choosing some from each. the rules contradict each other.

the html is generated by javascript

const toDoArray = {
  test: true,
}

var toDoElements = "<table style=\"width: 100%;\">";

for (var k in toDoArray) { // Loop through the object
  var trS = "";
  if (toDoArray[k]) {
    trS = `class="taskChecked"`
  }
  toDoElements +=
    `<tr ${trS} id="${k}-tr">
      <td onclick="checkOffToDo('${k}')" id = "${k}-td" border=none > ${k}</td>
      <td onclick="removeToDo('${k}')" class="toDoDeleteButton">&times;</td>     
    </tr>`
}

toDoElements += "</table>";

document.getElementById("toDoList").innerHTML = toDoElements;
#toDoList { width: 200px; font-size: 3rem; }

.taskChecked {
  text-decoration: line-through;
  text-decoration-color: violet;
  color: purple;
  background: orange;
}

.toDoDeleteButton {
  border: none;
  width: 8%;
  height: auto;
  text-decoration: none !important;
  text-decoration-color: aqua;
  color: yellow;
  background-color: blue;
}
<div id="toDoList"></div>

A yellow "x" with a violet strikethrough on a blue background

I found this StackOverflow Answer describing precedence (https://stackoverflow.com/a/25105841), but this doesn't seem follow it. If it followed all one, or all the other, I thought I could get it to work right, but now I'm just really confused.

My chief aim is to not give it a line through. the rest of the colors and stuff are me testing options trying to figure out what's going on, and why its not working.

This is in Chrome.


Solution

  • Quote from MDN link:

    Text decorations are drawn across descendant text elements. This means that if an element specifies a text decoration, then a child element can't remove the decoration.

    So, even though your <td> element specifies text-decoration: none, the text inside the <td> is still affected by the text-decoration of the <tr> element.

    However, according to this specification:

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

    So a workaround is to add an inline-block element. For example, we can use a span element and style it as inline-block. And since there is nothing special about the span, the sizes of the other elements are the same before.

    const toDoArray = {
      test: true,
    }
    
    var toDoElements = "<table style=\"width: 100%;\">";
    
    for (var k in toDoArray) { // Loop through the object
      var trS = "";
      if (toDoArray[k]) {
        trS = `class="taskChecked"`
      }
      toDoElements +=
        `<tr ${trS} id="${k}-tr">
          <td onclick="checkOffToDo('${k}')" id = "${k}-td" border=none > ${k}</td>
          <td onclick="removeToDo('${k}')" class="toDoDeleteButton"><span>&times;</span></td>     
        </tr>`
    }
    
    toDoElements += "</table>";
    
    document.getElementById("toDoList").innerHTML = toDoElements;
    #toDoList { width: 200px; font-size: 3rem; }
    
    .taskChecked {
      text-decoration: line-through;
      text-decoration-color: violet;
      color: purple;
      background: orange;
    }
    
    .toDoDeleteButton {
      border: none;
      width: 8%;
      height: auto;
      text-decoration-color: aqua;
      color: yellow;
      background-color: blue;
    }
    
    .toDoDeleteButton > span{
      display: inline-block;
    }
    <div id="toDoList"></div>

    I found that you don't even need .toDoDeleteButton > span {text-decoration: none;}.
    The text-decoration doesn't propagate to the span, unless you specify text-decoration: inherit for both the td and the span.