2015-07-13 94 views
20

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>

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

+0

你能提供JSFiddle上的代码示例吗? –

+0

https://jsfiddle.net/fzax9qj1/ – Deadpool

+0

你用jQuery标记了这个 - 你可以添加你自己的空检查谓词,如果这可以满足你的目的。 – Pointy

回答

15

尽管问题描述了一个包含少数常规空格字符的<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>元素不会产生相同的节点树,尤其是第一个不导致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或生成它的应用程序(特别是如果您最终必须实施和测试特殊情况才行)。

如前所述,:blank pseudo-class in Selectors 4将解决此问题。不幸的是,它没有达到目前的标准,要么是因为它没有提前提出,要么根本没有机会实现它。即使它的名字还没有最终确定,目前尚不清楚所描述的行为是否已经过测试或最终确定。

由于它是一个相对较新的建议标准,也有:-moz-only-whitespace之外没有已知的实现,为此,MDN具有this说:

:-moz-only-whitespace伪类没有子元素相匹配所有节点或空文本节点或文本节点只有空白。只有当元素节点或文本节点中包含一个或多个字符时,该元素才会与此伪类不再匹配。

...这,仔细观察,确实出现了与:blank规范的描述是一致的,但因为它是非标准的,并没有什么还没有最终确定我会建议对在生产中使用它。

因为它没有在其他地方实现,所以在其他任何浏览器中都没有相应的功能。与此同时,修改HTML 唯一的选择,无论是源代码还是通过使用脚本的DOM操作。

2

@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("*"); 

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

例如,我正在使用WordPress,并且一些内部页面中有一些垃圾。幸运的是,他们都是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); 

再次,如果你发现我的代码的任何问题,请让我知道在下面的意见。

希望这会有所帮助!

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

+1

重写'innerHTML'是不好的。您将删除所有内部数据,如事件侦听器,检查,自定义属性等。正确的方法是迭代DOMContentLoaded中的所有文本节点,并删除仅包含空白的文本节点。然后':空'会起作用。 – Oriol

+0

好点@Oriol。正如我所说,这不是最好的方法。我应该编辑我的答案,更具体的目标文本节点。 – WebWanderer