Line 3 is a hidden What is the best approach to get t
odd/even css rule.
Another way, albeit on the fringe side, is to have an extra <tbody> and either move or copy rows there. Or, an extra div wrapper if using OPs example. Copying easiest of course in regards to restoring etc.
This approach can be useful in some cases.
Below is a simple example where rows are moved when filtered. And yes, it is ranking of stripper names, found it fitting as we are talking stripes ... hah
const Filter = {
table: null,
last: {
tt: null,
value: ''
},
name: function (txt) {
let tb_d = Filter.table.querySelector('.data'),
tb_f = Filter.table.querySelector('.filtered'),
tr = tb_d.querySelectorAll('TR'),
f = 0
;
tb_f.innerHTML = '';
if (txt.trim() == '') {
tb_d.classList.remove('hide');
} else {
txt = txt.toLowerCase();
for (let i = 0; i < tr.length; ++i) {
let td = tr[i].querySelectorAll('TD')[1];
if (td.textContent.toLowerCase().includes(txt)) {
tb_f.appendChild(tr[i].cloneNode(true));
f = 1;
}
}
if (f)
tb_d.classList[f ? 'add' : 'remove']('hide');
}
},
key: function (e) {
const v = e.target.value;
if (v == Filter.last.value)
return;
Filter.last.value = v;
clearTimeout(Filter.last.tt);
Filter.last.tt = setTimeout(function () { Filter.name(v); }, 200);
}
};
Filter.table = document.getElementById('table');
Filter.table.addEventListener('keyup', Filter.key);
table {
width: 200px;
border: 3px solid #aaa;
}
tbody tr { background: #e33; }
tbody tr:nth-child(even) { background: #e3e; }
.hide { display: none; }
<table id="table">
<thead>
<tr><th></th><th><input type="text" id="filter" data-keyup="filter" /></th></tr>
<tr><th>#</th><th>Name</th></tr>
</thead>
<tbody class="filtered">
</tbody>
<tbody class="data">
<tr><td>1</td><td>Crystal</td></tr>
<tr><td>2</td><td>Tiffany</td></tr>
<tr><td>3</td><td>Amber</td></tr>
<tr><td>4</td><td>Brandi</td></tr>
<tr><td>5</td><td>Lola</td></tr>
<tr><td>6</td><td>Angel</td></tr>
<tr><td>7</td><td>Ginger</td></tr>
<tr><td>8</td><td>Candy</td></tr>
</tbody>
</table>
As @Fateh Khalsa pointed out, I had a similar problem and since I was manipulating my table with JavaScript (jQuery to be precise), I was able to do the following:
(Note: This assumes use of JavaScript/jQuery which the OP did not state whether or not would be available to them. This answer assumes yes, it would be, and that we may want to toggle visibility of hidden rows at some point.)
This process is then reversed when the link is clicked again.
Here's the JavaScript (jQuery) to do this:
// Inactive Row Toggle
$('.toginactive').click(function(e) {
e.preventDefault();
if ($(this).hasClass('on')) {
$(this).removeClass('on'); // Track that we're no longer hiding rows
$('.wrap tr.hideme').removeClass('hidden'); // Remove hidden class from inactive rows
$('.wrap tr.skiprowcolor').remove(); // Remove extra rows added to fix coloring
} else {
$(this).addClass('on'); // Track that we're hiding rows
$('.wrap tr.hideme').addClass('hidden'); // Add hidden class from inactive rows
$('.wrap tr.hideme').after('<tr class="hidden skiprowcolor"></tr>');
// Add extra row after each hidden row to fix coloring
}
});
The HTML link is simple
<a href="#" class="toginactive">Hide/Show Hidden Rows</a>
:nth-child() pseudo-class looks through the children tree of the parent to match the valid child (odd, even, etc), therefore when you combine it with :not(.hidden) it won't filter the elements properly.
Alternatively, we could fake the effect by CSS gradient as follows:
.hidden {display:none;}
.wrap {
line-height: 1.2em;
background-color: orange;
background-image: linear-gradient(transparent 50%, green 50%);
background-size: 100% 2.4em;
}
<div class="wrap">
<div class="box">xx</div>
<div class="box">xx</div>
<div class="box hidden">xx</div>
<div class="box">xx</div>
<div class="box">xx</div>
<div class="box">xx</div>
<div class="box">xx</div>
</div>
Here's a CSS-only solution:
.box {
background: orange;
}
.box:nth-child(even) {
background: green;
}
.box.hidden {
display: none;
}
.box.hidden ~ .box:nth-child(odd) {
background: green;
}
.box.hidden ~ .box:nth-child(even) {
background: orange;
}
<div class="wrap">
<div class="box">xx</div>
<div class="box">xx</div>
<div class="box hidden">xx</div>
<div class="box">xx</div>
<div class="box">xx</div>
<div class="box">xx</div>
<div class="box">xx</div>
</div>
scss for @tim answer's above, to keep class name changes to a minimum
$selector: "box";
$hidden-selector: "hidden";
.#{$selector} {
background: orange;
:nth-child(even) {
background: green;
}
&.#{$hidden-selector} {
display: none;
}
&.#{$hidden-selector} ~ {
.#{$selector} {
&:nth-of-type(odd) {
background: green;
}
&:nth-of-type(even) {
background: orange;
}
}
}
}
Since my rows are being hidden with js, I found that the easiest approach for me was to just add an additional hidden row after each real row that I hide, and remove the hidden rows when I show the real rows again.