【问题标题】:CSS selector for empty or whitespace空或空白的 CSS 选择器
【发布时间】:2015-10-01 16:31:41
【问题描述】:

我们有一个选择器: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:In JSFiddle

【问题讨论】:

  • 能否提供 JSFiddle 上的代码示例?
  • 目前,我找不到:blankCSS Level 4 Selectors 的一部分,但仍未实现AFAIK。
  • “数据来自 php 后端,在某些情况下,它不是表格列中的空白,而是发送带有空格的内容”似乎正确的方法是在后端
  • 您不应为此目的在您的问题中添加不相关的标签。这不适合使用标签。

标签: html css css-selectors


【解决方案1】:

很多人都忽略了这个问题的要点,我在下面的说明中已经谈到了这个问题,但是对于那些只是在寻找答案的人,我在这里复制最后一段:

Selectors 4 now redefines :empty 包含仅包含空格的元素。这最初是作为一个单独的伪类 :blank 提出的,但在确定根据原始行为在没有太多站点的情况下这样做是安全的之后,最近又将其重新转换为 :empty。浏览器将需要更新其:empty 的实现以符合选择器4。如果您需要支持较旧的浏览器,您将不得不经历标记仅包含空格的元素或在事实之前或之后修剪空格的麻烦.


虽然问题描述了一个包含少量常规空格字符的 &lt;p&gt; 元素,这似乎是一个疏忽,但更常见的是看到元素仅包含缩进和空行形式的空格的标记,例如:

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

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

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

鉴于HTML considers inter-element whitespace to be transparent by design,希望使用 CSS 来定位此类元素而不需要修改 HTML 或生成它的应用程序并不是不合理的(尤其是如果您最终不得不实现和测试一个特殊情况只是为了做所以)。为此,Selectors 4 now redefines:empty 包含仅包含空格的元素。这最初是作为一个单独的伪类 :blank 提出的,但在确定根据原始行为在没有太多站点的情况下这样做是安全的之后,最近被重新连接到 :empty。浏览器将需要更新其:empty 的实现以符合选择器4。如果您需要支持较旧的浏览器,您将不得不经历标记仅包含空格的元素或在事实之前或之后修剪空格的麻烦.

【讨论】:

  • 恕我直言,这需要一个简短的回答,无论解释如何。 TL;DR 或者你有什么。
  • :blank 不再像这里描述的那样工作。现在它指的是输入及其值。 drafts.csswg.org/selectors-4/#changes-2018-02
  • @Kevin Beal:谢谢,我已经更新了答案以反映这一变化。
  • @Carles Alcolea:我在答案的顶部添加了一个摘要。我发布这个解释主要是因为看到 cmets 中有这么多人错过了问题的重点而感到沮丧。
  • :empty 不适用于我在 Ubuntu 20 上的 Firefox 87 中填充空格的 &lt;dd&gt; &lt;/dd&gt; 项目。但 -moz-... 可以。
【解决方案2】:

@BoltClock 为这个问题提供了一个绝妙的答案,表明这一点(目前,即使用 CSS 规范 3)无法仅通过 CSS 来实现。

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

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

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

我将介绍如何自己编写脚本的步骤...

首先,在页面加载后启动一切。

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

window.addEventListener("load", cleanUpMyDOM);

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

第二,收集我们正在检查的元素。

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

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

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

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

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

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

我们将为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);

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

希望这会有所帮助!

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

【讨论】:

  • 重写innerHTML 是不好的。您将删除所有内部数据,如事件侦听器、检查性、自定义属性等。正确的方法是在 DOMContentLoaded 处迭代所有文本节点,并删除仅包含空格的节点。然后:empty 就可以了。
  • 好点@Oriol。正如我所说,这不是最好的方法。我应该编辑我的答案以更具体地定位文本节点。
猜你喜欢
  • 1970-01-01
  • 2019-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-29
  • 2013-07-15
  • 1970-01-01
  • 2018-05-17
相关资源
最近更新 更多