空白或空格的 CSS 选择器

新手上路,请多包涵

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

 <p></p>

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

 <p>    </p>

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

 :empty { width: 300px; height: 15px; background: blue; }
:-moz-only-whitespace { width: 300px; height: 15px; background: orange; }
 <p></p>
<p>    </p>
<p>This is paragraph three.</p>

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

PS: 在 JSFiddle 中

原文由 Deadpool 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 613
2 个回答

很多人都忽略了这个问题的要点,我在下面的阐述中已经解决了这个问题,但是对于那些只是在寻找答案的人,我在这里反映了最后一段:

Selectors 4 现在重新定义 :empty 以包括仅包含空格的元素。这最初被提议作为一个单独的伪类 :blank 但最近被重新连接到 :empty 在确定根据原始行为没有太多站点这样做是安全的之后。浏览器将需要更新他们对 :empty 的实现以符合 Selectors 4。如果你需要支持旧的浏览器,你将不得不经历标记只包含空格的元素或在之前修剪空格的麻烦或事后。


虽然问题描述了一个 <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>

某些元素,如上例中的 <li> 以及 <p> ,具有可选的结束标记,这可能会在 DOM 处理以及元素间空白的情况下导致意外的副作用.例如,以下两个 <ul> 元素不会产生等效的节点树,特别是第一个不会在选择器级别 3 中产生 li:empty

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

鉴于 HTML 认为元素间空白在设计上是透明的,因此希望使用 CSS 定位此类元素而不必求助于修改 HTML 或生成它的应用程序(尤其是如果您最终必须实现和测试一个特殊情况只是这样做)。为此, Selectors 4 现在重新定义 :empty 以包含仅包含空格的元素。这最初被提议作为一个单独的伪类 :blank 但最近被重新连接到 :empty 在确定根据原始行为没有太多站点这样做是安全的之后。浏览器将需要更新他们对 :empty 的实现以符合 Selectors 4。如果你需要支持旧的浏览器,你将不得不经历标记只包含空格的元素或在之前修剪空格的麻烦或事后。

原文由 BoltClock 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

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

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

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

我将逐步介绍如何自己编写脚本…

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

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

 window.addEventListener("load", cleanUpMyDOM);

…当然,在此之前,创建一个名为 functioncleanUpMyDOM 。我们将在此函数中编写其余的逻辑。

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

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

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

 var nodes = document.querySelectorAll("*");

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

例如,我正在使用 WordPress,一些内部页面中有一些垃圾。 Luckily, they are all p elements that are children of a div.body element, so I can change my selector to document.querySelectorAll("div.body p") , which will select only 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";
}

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

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

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

 .blank {
    display:none;
}

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

对于那些只想继续前进的人,这是完成的脚本:

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

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

希望这可以帮助!

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

原文由 WebWanderer 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题