Проблема с CSS (nth-of-type) при фильтрации элементов в таблице

Рейтинг: 1Ответов: 2Опубликовано: 09.04.2023

Есть примерно такая таблица с фильтрацией по категориям:

<!DOCTYPE html>
<html lang="en" >

<style>
.responsive-table tbody tr:nth-of-type(even) {
   background-color: rgba(0, 0, 0, 0.12);
}

table {
  width: 100%;
  border-collapse: collapse;
}
td, th {
  padding: 3px;
  border: 1px solid black;
   }

input[type="radio"] {
  position: absolute;
  left: -9999px;
}
.filters {
  text-align: center;
  margin-bottom: 2rem;
}
.filters * {
  display: inline-block;
}
.filters label {
  padding: 0.5rem 1rem;
  margin-bottom: 0.25rem;
  border-radius: 2rem;
  min-width: 50px;
  line-height: normal;
  cursor: pointer;
  transition: all 0.1s;
}
.filters label:hover {
  background: green;
  color: white;
}
[value="All"]:checked ~ .filters [for="All"],
[value="30s"]:checked ~ .filters [for="30s"],
[value="40s"]:checked ~ .filters [for="40s"],
[value="50s"]:checked ~ .filters [for="50s"] {
  background: green;
  color: white;
}
[value="All"]:checked ~ .bodyTable [data-category] {
  display: table;
}
[value="30s"]:checked ~ .responsive-table .bodyTable .cat:not([data-category~="30s"]),
[value="40s"]:checked ~ .responsive-table .bodyTable .cat:not([data-category~="40s"]),
[value="50s"]:checked ~ .responsive-table .bodyTable .cat:not([data-category~="50s"]) {
  display: none;
}
</style>

<body>

<input type="radio" id="All" name="categories" value="All" checked>
<input type="radio" id="30s" name="categories" value="30s">
<input type="radio" id="40s" name="categories" value="40s">
<input type="radio" id="50s" name="categories" value="50s">

<ol class="filters">
<li><label for="All">All</label></li>
<li><label for="30s">30s</label></li>
<li><label for="40s">40s</label></li>
<li><label for="50s">50s</label></li>
</ol>

  <table class="responsive-table">
    <tbody class="bodyTable">
      <tr class="cat" data-category="30s">
        <th>1. 30s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
      <tr class="cat" data-category="40s">
        <th>2. 40s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
      <tr class="cat" data-category="40s">
        <th>3. 40s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
      <tr class="cat" data-category="50s">
        <th>4. 50s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
      <tr class="cat" data-category="30s">
        <th>5. 30s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
      <tr class="cat" data-category="40s">
        <th>6. 40s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
      <tr class="cat" data-category="40s">
        <th>7. 40s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
      <tr class="cat" data-category="50s">
        <th>8. 50s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
      <tr class="cat" data-category="30s">
        <th>9. 30s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
      <tr class="cat" data-category="50s">
        <th>10. 50s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
      <tr class="cat" data-category="50s">
        <th>11. 50s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
      <tr class="cat" data-category="50s">
        <th>12. 50s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
      <tr class="cat" data-category="40s">
        <th>13. 40s</th>
        <td>...........................</td>
        <td>...........................</td>
      </tr>
    </tbody>
  </table>  

</body>
</html>

Каждая чётная строка выделена другим цветом (при показе всей таблицы - значение All). Как это правило соблюсти при фильтрации (в категориях 30s, 40s, 50s)?

Ответы

▲ 0Принят

На текущий момент (апрель 2023), нет универсального (читай, для разных браузеров и их версий) решения раскрасить в "зебру" динамическую таблицу, не прибегая к скриптам.


jQuery и :visible

Пока мы ждём нативный псевдокласс :visible для CSS, в jQuery такой селектор давно существует:

$('[name="categories"]').on('change', function() {
  $('.cat').css("background-color", "").filter(':visible').odd().css("background-color", "rgba(0, 0, 0, 0.12)");
}).trigger( "change" );
table {
  width: 100%;
  border-collapse: collapse;
}

td,
th {
  padding: 3px;
  border: 1px solid black;
}

input[type="radio"] {
  position: absolute;
  left: -9999px;
}

.filters {
  text-align: center;
  margin-bottom: 2rem;
}

.filters * {
  display: inline-block;
}

.filters label {
  padding: 0.5rem 1rem;
  margin-bottom: 0.25rem;
  border-radius: 2rem;
  min-width: 50px;
  line-height: normal;
  cursor: pointer;
  transition: all 0.1s;
}

.filters label:hover {
  background: green;
  color: white;
}

[value="All"]:checked~.filters [for="All"],
[value="30s"]:checked~.filters [for="30s"],
[value="40s"]:checked~.filters [for="40s"],
[value="50s"]:checked~.filters [for="50s"] {
  background: green;
  color: white;
}

[value="30s"]:checked~.responsive-table .bodyTable .cat:not([data-category~="30s"]),
[value="40s"]:checked~.responsive-table .bodyTable .cat:not([data-category~="40s"]),
[value="50s"]:checked~.responsive-table .bodyTable .cat:not([data-category~="50s"]) {
  display: none;
}
<script src="https://code.jquery.com/jquery-3.6.3.js"></script>
<input type="radio" id="All" name="categories" value="All" checked>
<input type="radio" id="30s" name="categories" value="30s">
<input type="radio" id="40s" name="categories" value="40s">
<input type="radio" id="50s" name="categories" value="50s">

<ol class="filters">
  <li><label for="All">All</label></li>
  <li><label for="30s">30s</label></li>
  <li><label for="40s">40s</label></li>
  <li><label for="50s">50s</label></li>
</ol>

<table class="responsive-table">
  <tbody class="bodyTable">
    <tr class="cat" data-category="30s">
      <th>1. 30s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>2. 40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>3. 40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>4. 50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="30s">
      <th>5. 30s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>6. 40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>7. 40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>8. 50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="30s">
      <th>9. 30s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>10. 50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>11. 50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>12. 50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>13. 40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
  </tbody>
</table>

CSS и :nth-child(n of selector)

Существует другой способ - использовать :nth-child(n of selector). Проблема в том, что псевдокласс с таким параметром поддерживают только самые современные браузеры, (которые, в свою очередь, требуют установленной Windows версии 10 и новее).

.responsive-table tbody tr:nth-of-type(2n) {
  background-color: rgba(0, 0, 0, 0.12);
}

table {
  width: 100%;
  border-collapse: collapse;
}

td,
th {
  padding: 3px;
  border: 1px solid black;
}

input[type="radio"] {
  position: absolute;
  left: -9999px;
}

.filters {
  text-align: center;
  margin-bottom: 2rem;
}

.filters * {
  display: inline-block;
}

.filters label {
  padding: 0.5rem 1rem;
  margin-bottom: 0.25rem;
  border-radius: 2rem;
  min-width: 50px;
  line-height: normal;
  cursor: pointer;
  transition: all 0.1s;
}

.filters label:hover {
  background: green;
  color: white;
}

[value="All"]:checked~.filters [for="All"],
[value="30s"]:checked~.filters [for="30s"],
[value="40s"]:checked~.filters [for="40s"],
[value="50s"]:checked~.filters [for="50s"] {
  background: green;
  color: white;
}

[value="All"]:checked~.bodyTable [data-category] {
  display: table;
}

[value="30s"]:checked~.responsive-table .bodyTable .cat:not([data-category~="30s"]),
[value="40s"]:checked~.responsive-table .bodyTable .cat:not([data-category~="40s"]),
[value="50s"]:checked~.responsive-table .bodyTable .cat:not([data-category~="50s"]) {
  display: none;
}
/* На 10.04.2023 работает только в Chrome 111, Edge 111, Safari 9 */
[value="30s"]:checked~.responsive-table .bodyTable tr:nth-child(2n of [data-category="30s"]),
[value="40s"]:checked~.responsive-table .bodyTable tr:nth-child(2n of [data-category="40s"]),
[value="50s"]:checked~.responsive-table .bodyTable tr:nth-child(2n of [data-category="50s"]) {
  background-color: rgba(0, 0, 0, 0.12);
}
<input type="radio" id="All" name="categories" value="All" checked>
<input type="radio" id="30s" name="categories" value="30s">
<input type="radio" id="40s" name="categories" value="40s">
<input type="radio" id="50s" name="categories" value="50s">

<ol class="filters">
  <li><label for="All">All</label></li>
  <li><label for="30s">30s</label></li>
  <li><label for="40s">40s</label></li>
  <li><label for="50s">50s</label></li>
</ol>

<table class="responsive-table">
  <tbody class="bodyTable">
    <tr class="cat" data-category="30s">
      <th>30s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="30s">
      <th>30s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="30s">
      <th>30s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
  </tbody>
</table>

CSS и repeating-linear-gradient()

Ну и наконец, если предполагается одинаковая высота для всех строк, то нет ничего проще, чем сделать таблице фон из повторяющегося градиента:

table {
  width: 100%;
  border-collapse: collapse;
  /* "Зебра" */
  background-image: repeating-linear-gradient(transparent 0 25px, rgba(0, 0, 0, 0.12) 25px 50px);
}

td,
th {
  padding: 3px;
  border: 1px solid black;
}

input[type="radio"] {
  position: absolute;
  left: -9999px;
}

.filters {
  text-align: center;
  margin-bottom: 2rem;
}

.filters * {
  display: inline-block;
}

.filters label {
  padding: 0.5rem 1rem;
  margin-bottom: 0.25rem;
  border-radius: 2rem;
  min-width: 50px;
  line-height: normal;
  cursor: pointer;
  transition: all 0.1s;
}

.filters label:hover {
  background: green;
  color: white;
}

[value="All"]:checked~.filters [for="All"],
[value="30s"]:checked~.filters [for="30s"],
[value="40s"]:checked~.filters [for="40s"],
[value="50s"]:checked~.filters [for="50s"] {
  background: green;
  color: white;
}

[value="All"]:checked~.bodyTable [data-category] {
  display: table;
}

[value="30s"]:checked~.responsive-table .bodyTable .cat:not([data-category~="30s"]),
[value="40s"]:checked~.responsive-table .bodyTable .cat:not([data-category~="40s"]),
[value="50s"]:checked~.responsive-table .bodyTable .cat:not([data-category~="50s"]) {
  display: none;
}
<input type="radio" id="All" name="categories" value="All" checked>
<input type="radio" id="30s" name="categories" value="30s">
<input type="radio" id="40s" name="categories" value="40s">
<input type="radio" id="50s" name="categories" value="50s">

<ol class="filters">
  <li><label for="All">All</label></li>
  <li><label for="30s">30s</label></li>
  <li><label for="40s">40s</label></li>
  <li><label for="50s">50s</label></li>
</ol>

<table class="responsive-table">
  <tbody class="bodyTable">
    <tr class="cat" data-category="30s">
      <th>30s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="30s">
      <th>30s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="30s">
      <th>30s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="50s">
      <th>50s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
    <tr class="cat" data-category="40s">
      <th>40s</th>
      <td>...........................</td>
      <td>...........................</td>
    </tr>
  </tbody>
</table>

▲ 0

Вот так правильно и если надо вертикально зебру сделать, тогда нужно применять к "td"

tr:nth-child(odd) {
  background: red;
}
tr:nth-child(even) {
  background: green;
}
<table>
  <tr>
    <td>Ячейка 1</td>
    <td>Ячейка 2</td>
    <td>Ячейка 3</td>
    <td>Ячейка 4</td>
  </tr>
  <tr>
    <td>Ячейка 1</td>
    <td>Ячейка 2</td>
    <td>Ячейка 3</td>
    <td>Ячейка 4</td>
  </tr>
  <tr>
    <td>Ячейка 1</td>
    <td>Ячейка 2</td>
    <td>Ячейка 3</td>
    <td>Ячейка 4</td>
  </tr>
  <tr>
    <td>Ячейка 1</td>
    <td>Ячейка 2</td>
    <td>Ячейка 3</td>
    <td>Ячейка 4</td>
  </tr>
</table>