2015-07-13 132 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