空选或空白的CSS选择器

Dea*_*ool 27 html css css-selectors

我们有一个选择器:empty,可以在元素完全为空时匹配它:

<p></p>
Run Code Online (Sandbox Code Playgroud)

但我有一个条件,它可能是空的,或者它可能包含换行符或空格:

<p>    </p>
Run Code Online (Sandbox Code Playgroud)

我找到了Firefox的解决方案,:-moz-only-whitespace:

:empty { width: 300px; height: 15px; background: blue; }
:-moz-only-whitespace { width: 300px; height: 15px; background: orange; }
Run Code Online (Sandbox Code Playgroud)
<p></p>
<p>    </p>
<p>This is paragraph three.</p>
Run Code Online (Sandbox Code Playgroud)

其他浏览器是否有类似的解决方案?

Bol*_*ock 19

虽然这个问题描述了一个<p>包含少数常规空格字符的元素,这似乎是一种疏忽,但更常见的是标记元素只包含缩进和空行形式的空格,例如:

<ul class="items">
  <li class="item">
    <div>
      <!-- Some complex structure of elements -->
    </div>
  </li>
  <li class="item">
  </li> <!-- Empty, except for a single line break and
             indentation preceding the end tag -->
</ul>
Run Code Online (Sandbox Code Playgroud)

某些元素(<li>如上例中的元素)以及<p>可选的结束标记可能会导致DOM处理中出现意外的副作用,并且存在元素间空白.例如,以下两个<ul>元素不会生成等效的节点树,特别是第一个元素不会导致li:empty:

li:empty::before { content: '(empty)'; font-style: italic; color: #999; }
Run Code Online (Sandbox Code Playgroud)
<ul>
  <li>
</ul>
<ul>
  <li></li>
</ul>
Run Code Online (Sandbox Code Playgroud)

鉴于HTML认为元素间空白在设计上是透明的,想要使用CSS来定位这些元素并不是不合理的,而不必诉诸于修改HTML或生成它的应用程序(特别是如果你最终必须实现和测试特殊情况就是这样).

如上所述,:blankSelectors 4中伪类将解决这个问题.不幸的是,它没有达到目前的标准,要么是因为它没有提前提出,要么就是没有机会充实它.即使它的名字还没有最终确定,并且不清楚所描述的行为是否已经过测试或最终确定.

由于这是一个相对较新的标准提案,因此没有已知的实现:-moz-only-whitespace,MDN对此有这样的说法:

:-moz-only-whitespace伪类匹配具有全部或空文本节点或在他们唯一的空白文本节点没有子节点的元素.只有当元素中有元素节点或文本节点有一个或多个字符时,该元素才会再与该伪类匹配.

...经过仔细检查,确实看起来与规范的描述一致:blank,但由于它是非标准的,尚未最终确定,我建议不要在生产中使用它.

由于它没有在其他地方实现,目前在任何其他浏览器中都没有相应的.与此同时,修改HTML 唯一的选择,无论是在源头,还是通过使用脚本的DOM操作.

  • **重要提示:** 尽管这个答案已经有近 7 年历史了,即使在最新的 Chrome 中,`:empty` 仍然具有旧的行为,即您必须删除所有空白才能被视为 `:empty`。允许注释,但不能有空格。 (4认同)
  • 恕我直言,这需要一个简短的答案,而不管其解释如何。TL; DR或您拥有什么。 (2认同)
  • 在 Ubuntu 20 上的 Firefox 87 中,`:empty` 对于充满空格的 `&lt;dd&gt; &lt;/dd&gt;` 项目不起作用。但是 `-moz-...` 可以。 (2认同)

Web*_*rer 5

@BoltClock 为这个问题提供了一个很好的答案,表明这(目前,即使用 CSS 规范 3)不能单独通过 CSS 实现。

@BoltClock 提到可以使用伪选择器定位真正为空的元素(正如所解释的,这是一个奇怪的定义):empty。这个伪选择器仅在 CSS 3 中可用,并且不会选择只有空格作为内容的元素。

@BoltClock 表示,清理只有空白作为内容的元素的唯一方法是修复 HTML,但这并不完全正确。这也可以通过 Javascript 的实现来实现。

记住!我提供的用于解决此问题的 Javascript 可能需要很长时间才能执行,因此最好的方法是尽可能清理原始 HTML。如果这是不可能的,那么这可能是一种解决方案,只要您没有过多的 DOM 树。

我将逐步完成如何自己编写脚本的步骤...

首先,在页面加载后启动所有内容。

这应该是很明显的。在运行脚本之前,您需要确保 DOM 已完全加载。添加一个event listener页面加载:

window.addEventListener("load", cleanUpMyDOM);
Run Code Online (Sandbox Code Playgroud)

...当然,在此之前,创建一个function被调用的cleanUpMyDOM. 我们将在此函数中编写其余的逻辑。

其次,收集我们正在检查的元素。

在我们的示例中,我们将检查整个 DOM,但这是我们的脚本可能变得非常广泛并且可能使您的页面无响应的地方。您可能希望限制迭代的节点数量。

我们可以使用document.querySelectorAll. 这个函数的好处在于它可以平衡 DOM 树,我们不必递归每个节点的子节点。

var nodes = document.querySelectorAll("*");
Run Code Online (Sandbox Code Playgroud)

正如我之前所说,这段代码将抓取每个 DOM 节点,这可能不是一个好主意。

例如,我正在使用 WordPress,其中一些内部页面中有一些垃圾。幸运的是,它们都是p元素的子div.body元素,因此我可以将我的选择器更改为document.querySelectorAll("div.body p"),这将仅递归地选择p作为我div.body元素的子元素的元素。这将大大优化我的脚本。

第三,迭代节点并找到空节点。

我们将为nodes数组创建一个循环并检查其中的每个节点。然后我们必须检查节点是否为空。如果它是空的,我们将应用一个名为 的类blank

我只是从这里开始拍摄,所以如果您发现此代码中有错误,请告诉我。

for(var i = 0; i < nodes.length; i++){
    nodes[i].innerHTML = nodes[i].innerHTML.trim();
    if(!nodes[i].innerHTML)
        nodes[i].className += " blank";
}
Run Code Online (Sandbox Code Playgroud)

我确信有一种更简洁的方法来编写上面的循环,但这应该可以完成工作。

最后,您需要做的就是使用 CSS 定位空白元素。

将此规则添加到您的样式表中:

.blank {
    display:none;
}
Run Code Online (Sandbox Code Playgroud)

你有它!您所有的“空白”节点都已隐藏。

对于那些只想跳到前面的人,这里是完成的脚本:

function cleanUpMyDOM(){
    var nodes = document.querySelectorAll("*");
    for(var i = 0; i < nodes.length; i++){
        nodes[i].innerHTML = nodes[i].innerHTML.trim();
        if(!nodes[i].innerHTML)
            nodes[i].className += " blank";
    }
}
window.addEventListener("load", cleanUpMyDOM);
Run Code Online (Sandbox Code Playgroud)

再一次,如果您发现我的代码有任何问题,请在下面的评论中告诉我。

希望这可以帮助!

PS许多人可能想知道您为什么要这样做,因为这确实是一种不好的做法。我会避免这样做,但我正处于开始考虑它的情况。我网站上的页面内容是通过 WYSIWYG 编辑器创建的。这些内容是由营销团队不断创建和修改的,我在处理对他们失误的支持时感到非常不知所措。修复 WordPress 的 WYSIWYG 编辑器不是我的工作(我也不想),但我可以编写一个非常简单的脚本来为我处理一些工作。除了培训支持团队在编辑时管理他们的空白之外,这对我来说绝对是更好的答案。

  • 重写 `innerHTML` 是不好的。您将删除所有内部数据,例如事件侦听器、检查性、自定义属性等。正确的方法是迭代 DOMContentLoaded 处的所有文本节点,并删除仅包含空格的文本节点。然后 `:empty` 就可以工作了。 (3认同)