选择奇偶子元素但不包括隐藏的子元素

33

第3行是一个隐藏的<div>。我不希望它被odd/even css规则所影响。

在这里输入图片描述

如何最好地解决这个问题?

.hidden {display:none;}
.box:not(.hidden):nth-child(odd)  { background: orange; }
.box:not(.hidden):nth-child(even) { background: green;  }
<div class="wrap">
    <div class="box">1</div>
    <div class="box">2</div>
    <div class="box hidden">3</div>
    <div class="box">4</div>
    <div class="box">5</div>
    <div class="box">6</div>
    <div class="box">7</div>
</div>

注意:可能会有多个hidden元素。

http://jsfiddle.net/k0wzoweh/


1
:nth-of-type奇数和偶数,试试这个 - http://jsfiddle.net/6dnaep2w/ - Anonymous
2
@MaryMelody不起作用,即使在你的fiddle中也是如此。伪选择器不会叠加。 - Joe
你能够使用.visible类并像这样做吗? - Albzi
1
你能否在其他div之前或之后添加一个额外的隐藏div吗?我不清楚你试图解决什么问题以及你面临什么限制。如果你想让可见的div交替出现而不希望隐藏的div变为可见,你应该明确说明。 - Reid
1
:nth-of-type仅适用于类型,因此它正在寻找div元素。如果隐藏的元素是一个p而不是一个div,@MaryMelody的解决方案将起作用。 - Paul
显示剩余3条评论
11个回答

43

:nth-child() 伪类会在父元素的子树中查找有效的子元素(oddeven等),因此当你将它与 :not(.hidden) 结合使用时,它将无法正确过滤元素。

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>


很不错的尝试,但遗憾的是它只在特定元素被隐藏且没有其他元素时才有效。如果有两个相邻的隐藏行,它仍然会出现相同的错误。 - Balázs Varga
不适用于: `<div class="wrap"> <div class="box">xx</div> <div class="box hidden">xx</div> <div class="box">xx</div> <div class="box">xx</div> <div class="box hidden">xx</div> <div class="box">xx</div> <div class="box hidden">xx</div> <div class="box hidden">xx</div> <div class="box">xx</div></div>` - Ronny Sherer

16

伪选择器不能叠加,因此您的 :not 不会影响 :nth-child(也不会影响 :nth-of-type 等)。

如果可以使用jQuery,可以在那里使用:visible 伪选择器,尽管它不是CSS规范的一部分。

如果您正在生成HTML并且可以更改HTML,请使用运行时逻辑应用奇偶性,例如在PHP中:

foreach ($divs AS $i => $div) {
    echo '<div class="box ' . ($i % 2 ? 'even' : 'odd') . '">x</div>';
}

即使尝试做一些棘手的事情

.box[class='box']:nth-of-type(even)

无法工作,因为伪选择器甚至不能叠加到属性选择器上。

我不确定是否有纯CSS的方法可以做到这一点 - 我现在想不出任何方法。


在运行时应用偶数/奇数类不起作用,因为OP指出div可以被点击并消失,因此以下元素的颜色应该改变。这里只能使用Javascript。 - Paul
1
@Paul 在这种情况下,他已经在使用 JS 进行点击切换,因此在维护颜色方面使用它不应该是一个问题,至少 :-) - Joe
1
这正是我所想的,但如果没有更多的代码提供,猜测就很困难。我可以在SO上作为一个预言家赚到数百万。 :D - Paul
正确的 - 简单选择器不会堆叠。这适用于ID、类、属性和伪类。每个简单选择器都是独立操作的。我确定我在某个地方已经涵盖了这个问题,但天哪,重复的数量。 - BoltClock
@BoltClock 这只是违反直觉的问题,我猜。我们都习惯于...嗯,基本上就是 jQuery。它用可爱、干净的 $('.box:not(.hidden):even') 神器来满足我们的需求,让我们感到非常舒适,他们怎么敢这样:P - Joe
显示剩余2条评论

10

这里是一种纯CSS解决方案:

.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>


4
如果两个隐藏元素紧挨着,就不能正常工作:https://jsfiddle.net/nuxcskx5/;或者如果有多个“hidden”元素,也不能正常工作:https://jsfiddle.net/nuxcskx5/1/。 - caramba
原始问题并未要求多个隐藏元素。 - Tim
没错,我试着让问题简单明了。这只是在注释中提到的。我会更新问题的。对此很抱歉。 - caramba
1
好的,您可以使用此解决方案来处理多个隐藏元素。您只需要在每个隐藏元素出现时重复还原背景颜色即可。https://codepen.io/anon/pen/VXRBdR 会导致选择器变得非常长,但它确实有效。 - Felix Wienberg

9

由于我的行使用js被隐藏,我发现最简单的方法是在我隐藏每个真实行后添加一个额外的隐藏行,并在再次显示真实行时删除隐藏行。


我本来想回答这个问题,但看到了你的答案。很巧妙的做法,保留 CSS 并稍微修改 JavaScript! - Eduardo Poço

4

使用 .hide() 方法隐藏需要隐藏的行,然后调用

$("tr:visible:even").css( "background-color", "" ); // clear attribute for all rows

$("tr:visible:even").css( "background-color", "#ddddff" ); // set attribute for even rows

将您的表名添加到选择器中以使其更具体。使用:even会跳过标题行。

对我仍然有用。这是一个有用的替代方案,只在可见元素上使用.nth-child - Benjamin Goodacre
@caramba,也许对于 OP 没有帮助,但对于通过搜索在后来找到这个问题的大量人仍然有帮助。 - Majid Fouladpour

3
尝试选择器
.hidden {display:none;}
.box:nth-child(odd of :not(.hidden))  { background: orange; }
.box:nth-child(even of :not(.hidden)) { background: green; }

1
这似乎有效!谢谢(工作示例:https://jsfiddle.net/75zsu3gx/1/) - undefined

0

正如@Fateh Khalsa所指出的,我曾经遇到过类似的问题,由于我是使用JavaScript(具体来说是jQuery)来操作表格的,因此我能够做到以下几点:

(注意:这假设使用JavaScript/jQuery,而原帖并没有说明是否可用。本答案假设可以使用,并且我们可能想在某个时候切换隐藏行的可见性。)

  • 当前可见的是无效记录(使用CSS类“hideme”标识)。
  • 访问者单击链接以从列表中隐藏无效记录。
  • jQuery向“hideme”记录添加“hidden”CSS类。
  • jQuery在我们刚刚隐藏的行后立即向表格添加一个额外的空行,添加CSS类“hidden”(以便不显示)和“skiprowcolor”,以便我们可以轻松地识别这些额外的行。

当再次单击链接时,该过程将被反转。

  • 当前隐藏了无效记录(使用CSS类“hideme”标识)。
  • 访问者点击链接以显示列表中的无效记录。
  • jQuery将“hidden” CSS类从“hideme”记录中移除。
  • jQuery删除紧随我们刚刚显示的行后面的表格中的额外空行,该行由CSS类“skiprowcolor”标识。

以下是执行此操作的JavaScript(jQuery):

// 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
    }
});

HTML链接很简单

<a href="#" class="toginactive">Hide/Show Hidden Rows</a>

0

你可以使用现代CSS(2023年)来实现这一点。CSS规范的扩展允许你使用第二个选择器列表来指定应该由:nth-child()伪选择器计数的元素,就像这样:tr:nth-child(2n of tr.important)

官方语法如下::nth-child(<nth> [of <complex-selector-list>]?)

根据MDN的说法,这在所有主要浏览器中已经得到支持大约6个月,自2023年5月Firefox添加了支持以来。W3C CSS WG Draft

示例:

.hidden {
  display: none;
 }
 
tr:nth-child(even of :not(.hidden)){
  background: lightblue;
}
<table>
  <caption>Example of "of   &lt;selector&gt;" use</caption>
  <thead>
    <tr><th>Make</th><th>Model</th><th>Year</th></tr>
  </thead>
  <tbody>
    <tr><td>Subaru</td><td>Forester</td><td>2021</td></tr>
    <tr><td>Ford</td><td>Ranger</td><td>2019</td></tr>
    <tr class="hidden"><td>Nissan</td><td>Rogue</td><td>2015</td></tr>
    <tr><td>Porche</td><td>911 Turbo</td><td>2023</td></tr>
    <tr class="hidden"><td>Toyota</td><td>Corolla</td><td>2009</td></tr>
    <tr><td>Chevy</td><td>Astro</td><td>1999</td></tr>
  </tbody>
</table>


0

针对@tim上面的答案,使用scss可以将类名更改最小化。

$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;
      }
    }
  }
}

-1

另一种方法,虽然有些边缘,是添加一个额外的<tbody>,然后将行移动或复制到那里。或者,如果使用OP的示例,则可以添加额外的div包装器。当然,在恢复等方面,复制最容易。

这种方法在某些情况下非常有用。

以下是一个简单的示例,在该示例中,当过滤时移动行。是的,它是脱衣舞娘名称的排名,因为我们正在谈论条纹...哈哈

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>


@caramba:答案不在于过滤,过滤只是为了展示结果。增加了行之间的对比度,使其更加清晰明了。 - user3342816

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接