idionym idionym - 1 year ago 82
CSS Question

Change checked html table row with CSS

I am trying to change the style of input elements in a single when check box in said row is checked. I have tried many combinations of "~", "+", with and without class identifiers, to no avail. I know how to use Javascript to create a workaround, and I know CSS does not allow for ancestor selection for many good reasons, but I was wondering if you can use CSS in any manner to accomplish this task.



tr td input {
font-size: 20px;
font-family: helvetica;
padding: 5px;
}

tr td input[type=checkbox]:checked+tr td input.input-item {
color: red;
font-style: italic;
text-decoration: line-through;
}

<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8;charset=utf-8">
<title>Title</title>
</head>

<body>
<table>
<thead>
<tr>
<th><input type="checkbox" name="checklist-list" class="checkbox-box"></th>
<th>Item1</th>
<th>Item2</th>
</tr>
</thead>
<tbody>
<tr>
<td class="checkbox-td"><input type="checkbox" name="checklist-list" class="checkbox-box"></td>
<td class="item-td"><input class="input-item" type="text" value="Artificial"></td>
<td class="item-td"><input class="input-item" type="text" value="Amateurs"></td>
</tr>
<tr>
<td class="checkbox-td"><input type="checkbox" name="checklist-list" class="checkbox-box"></td>
<td class="item-td"><input class="input-item" type="text" value="Broken"></td>
<td class="item-td"><input class="input-item" type="text" value="Barriers"></td>
</tr>
<tr>
<td class="checkbox-td"><input type="checkbox" name="checklist-list" class="checkbox-box"></td>
<td class="item-td"><input class="input-item" type="text" value="Casual"></td>
<td class="item-td"><input class="input-item" type="text" value="Create"></td>
</tr>
</tbody>
<tfoot>
</tfoot>
</table>
</body>




Answer Source

Unfortunately, existing CSS combinators allow only selecting elements within one common parent element and later in the source order. There is currently no way to select an ancestor or a previous sibling of the element. So it's not possible to style the container (e.g. tr) based on the state of the content (e.g. input). It's possible to change the next inputs based on the state of the previous one (as shown in Ivan's answer), but only if they are in the same container, which makes it impossible to format them as different table cells (it can be done so with CSS Grid layout, though, but it would require even flatter markup structure since all grid items have to be children of one grid container).

There is one terribly hacky workaround for this based on the fact that <label> element can transfer the click to the linked <input> regardless its position in the source code. We can make actual checkboxes invisible, place them before the table, and then style any part of the table we need using following siblings and descendants combinators, and make labels look as if they were checkboxes. A quick demo/proof of concept:

tr td input {
  font-size: 20px;
  font-family: helvetica;
  padding: 5px;
}

[type="checkbox"] {
  position: absolute;
  clip: 0 0 0 0;
  width: 0;
  height: 0;
  overflow: hidden;
}

.fake-checkbox {
  display: inline-flex;
  width: .8em;
  height: .8em;
  border: 2px inset #ccc;
  justify-content: center;
  align-content: center;
  vertical-align: middle;
}

#checkbox0:checked ~ table [for="checkbox0"]::before,
#checkbox1:checked ~ table [for="checkbox1"]::before,
#checkbox2:checked ~ table [for="checkbox2"]::before {
  content: '✔';
  line-height: 1;
}

#checkbox0:checked ~ table #checkbox0-tr td input.input-item,
#checkbox1:checked ~ table #checkbox1-tr td input.input-item,
#checkbox2:checked ~ table #checkbox2-tr td input.input-item {
  color: red;
  font-style: italic;
  text-decoration: line-through;
}
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8;charset=utf-8">
  <title>Title</title>
</head>

<body>

  <input type="checkbox" name="checklist-list" class="checkbox-box" id="checkbox0">
  <input type="checkbox" name="checklist-list" class="checkbox-box" id="checkbox1">
  <input type="checkbox" name="checklist-list" class="checkbox-box" id="checkbox2">

  <table>
    <thead>
      <tr>
        <th><input type="checkbox" name="checklist-list" class="checkbox-box"></th>
        <th>Item1</th>
        <th>Item2</th>
      </tr>
    </thead>
    <tbody>
      <tr id="checkbox0-tr">
        <td class="checkbox-td"><label for="checkbox0" class="fake-checkbox"></label></td>
        <td class="item-td"><input class="input-item" type="text" value="Artificial"></td>
        <td class="item-td"><input class="input-item" type="text" value="Amateurs"></td>
      </tr>
      <tr id="checkbox1-tr">
        <td class="checkbox-td"><label for="checkbox1" class="fake-checkbox"></label></td>
        <td class="item-td"><input class="input-item" type="text" value="Broken"></td>
        <td class="item-td"><input class="input-item" type="text" value="Barriers"></td>
      </tr>
      <tr id="checkbox2-tr">
        <td class="checkbox-td"><label for="checkbox2" class="fake-checkbox"></label></td>
        <td class="item-td"><input class="input-item" type="text" value="Casual"></td>
        <td class="item-td"><input class="input-item" type="text" value="Create"></td>
      </tr>
    </tbody>
    <tfoot>
    </tfoot>
  </table>
</body>

But honestly, I wouldn't recommend using this approach in production.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download