Resetting Odd/Even Sequence in HTML Table

2019-07-04 16:57发布

问题:

I fear the answer is no, but just wanted to try and confirm.

I am setting every other row of a table to have a gray background.

table tr:nth-child(odd) {
    background-color: #eee;
}

This works fine, but there are also embedded header rows within the table. And I would like the odd/even pattern to reset and start again following each header row.

What I would really like is a style I could assign to my header rows to indicate the row numbers should start again at 1 on the next row.

Is there any CSS styling to specify that the odd/even row tracking should be reset this way?

Note: I know I could turn to jQuery or adding custom classes to rows in my table. I was just hoping for a CSS-only solution.

EDIT:

Some have requested that I should how the table it laid out. So I'll do that here. I don't understand how this helps as a table is pretty basic and I thought it was obvious that all rows were siblings of each other.

<table>
    <tr class="SectionHeader">
        <th>
        </th>
    </tr>
    <tr>
        <td>
        </td>
    </tr>
    <tr class="SectionHeader">
        <th>
        </th>
    </tr>
    <tr>
        <td>
        </td>
    </tr>
    <tr>
        <td>
        </td>
    </tr>
    <tr class="SectionHeader">
        <th>
        </th>
    </tr>
    <tr>
        <td>
        </td>
    </tr>
    <tr>
        <td>
        </td>
    </tr>
</table>

回答1:

The closest you can get to dynamic values in CSS is with counters, but counters can't be used with selectors. A selector is mostly static with the exception of dynamic pseudo-classes. You can't use CSS to set an arbitrary value that will affect how a selector matches elements.

As suggested in the comments, your table structure is better represented using multiple tbody elements, one for each section. This would also allow your existing :nth-child() selector to match the correct row elements:

<table>
  <tbody>
    <tr class="SectionHeader">
      <th scope="rowgroup">
    <tr>
      <td>
  <tbody>
    <tr class="SectionHeader">
      <th scope="rowgroup">
    <tr>
      <td>
    <tr>
      <td>
  <tbody>
    <tr class="SectionHeader">
      <th scope="rowgroup">
    <tr>
      <td>
    <tr>
      <td>
</table>
  • end tags omitted to keep things clean; FYI this is perfectly valid HTML
  • I kept the "SectionHeader" class name from your original markup, but note that the scope="rowgroup" attribute on each header cell provides the appropriate semantics where a class name does not


回答2:

Since you didn't demonstrate a DOM, I'm going to offer a solution that relies on a specific DOM structure:

If you can use <thead> and <tbody> elements, the issue becomes trivial.

tbody tr:nth-child(even) {
  background: gray;
}
<table>
  <tr>
    <th>Header element</th>
    <th>Header element</th>
  </tr>
  <tbody>
    <tr>
      <td>John</td>
      <td>Doe</td>
    </tr>
    <tr>
      <td>Jane</td>
      <td>Doe</td>
    </tr>
    <tr>
      <td>John</td>
      <td>Doe</td>
    </tr>
    <tr>
      <td>Jane</td>
      <td>Doe</td>
    </tr>
  </tbody>
  <tr>
    <th>Header element</th>
    <th>Header element</th>
  </tr>
  <tbody>
    <tr>
      <td>Longer Than The Usual John</td>
      <td>Doe</td>
    </tr>
    <tr>
      <td>Jane</td>
      <td>Doe</td>
    </tr>
  </tbody>
</table>



回答3:

Since the consensus seems to be that it can't be done with CSS alone without changing the layout of the table, I couldn't help but rise to the challenge, so here it is.

tr.SectionHeader,
tr.SectionHeader + tr:not(.SectionHeader) + tr:not(.SectionHeader),
tr.SectionHeader + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader),
tr.SectionHeader + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader),
tr.SectionHeader + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader),
tr.SectionHeader + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader),
tr.SectionHeader + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader),
tr.SectionHeader + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) + tr:not(.SectionHeader) {
  background:#EEE}
<table>
    <tr class="SectionHeader">
        <th>hdr
        </th>
    </tr>
    <tr class="SectionHeader">
        <th>hdr
        </th>
    </tr>
    <tr>
        <td>cell
        </td>
    </tr>
    <tr class="SectionHeader">
        <th>hdr
        </th>
    </tr>
    <tr>
        <td>cell
        </td>
    </tr>
    <tr>
        <td>cell
        </td>
    </tr>
    <tr class="SectionHeader">
        <th>hdr
        </th>
    </tr>
    <tr>
        <td>cell
        </td>
    </tr>
    <tr>
        <td>cell
        </td>
    </tr>
    <tr>
        <td>cell
        </td>
    </tr>
    <tr class="SectionHeader">
        <th>hdr
        </th>
    </tr>
    <tr>
        <td>cell
        </td>
    </tr>
    <tr>
        <td>cell
        </td>
    </tr>
    <tr>
        <td>cell
        </td>
    </tr>
    <tr>
        <td>cell
        </td>
    </tr>
</table>

(Works with sequences of up to 14 non-header rows. If you need more, just add more CSS.)