CSS Selector for Empty or Whitespace

CSS selector for empty or whitespace

Lots of people missing the point of this question, which I've addressed in the following exposition, but for those just looking for the answer, I'm mirroring the last paragraph here:

Selectors 4 now redefines :empty to include elements that contain only whitespace. This was originally proposed as a separate pseudo-class :blank but was recently retconned into :empty after it was determined that it was safe to do so without too many sites depending on the original behavior. Browsers will need to update their implementations of :empty in order to conform to Selectors 4. If you need to support older browsers, you will have to go through the hassle of marking elements containing only whitespace or pruning the whitespace before or after the fact.


While the question depicts a <p> element containing a handful of regular space characters, which seems like an oversight, it is far more common to see markup where elements contain only whitespace in the form of indentation and blank lines, such as:

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

Some elements, like <li> in the above example as well as <p>, have optional end tags, which can cause unintended side effects in DOM processing as well in the presence of inter-element whitespace. For example, the following two <ul> elements don't produce equivalent node trees, in particular the first one does not result in a li:empty in Selectors level 3:

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

<li>

</ul>

<ul>

<li></li>

</ul>

:empty doesn't work if there's blank spaces?

As the others mentioned, this isn't possible with CSS yet.
You can check to see if there's only whitespace with JavaScript however. Here's a simple JS only solution, "empty" divs that match are blue, while divs that have text are red. Updated to add an empty class to the empty divs, which would allow you to target them easily with the selector .empty in your CSS.

The JS only "empty" comparison would look like this:

if(element.innerHTML.replace(/^\s*/, "").replace(/\s*$/, "") == "")

And if you're using jQuery it would be a bit easier:

if( $.trim( $(element).text() ) == "" ){

var navs = document.querySelectorAll(".nav-previous");

for( i=0; i < navs.length; i++ ){

if(navs[i].innerHTML.replace(/^\s*/, "").replace(/\s*$/, "") == "") {

navs[i].style.background = 'blue';

navs[i].classList.add( 'empty' );

} else {

navs[i].style.background = 'red';

}

}
.nav-previous {

padding: 10px;

border: 1px solid #000;

}

.nav-previous.empty {

border: 5px solid green;

}
<div class="nav-previous">

</div>

<div class="nav-previous">Not Empty </div>

Whitespace in CSS selectors

All of your conclusions are correct. There are nuances with regard to whitespace in attribute selectors, covered in my answer to this question.

All the exact rules of where whitespace may or may not appear are covered in the grammar. For the purposes of the grammar, the "contextual characters (such as + and >)" that you refer to are officially known as combinators. (The term "contextual selector" was first used in CSS1 but hasn't appeared since.)

Remember in addition that any number of contiguous whitespace characters that separate two simple selectors is considered a descendant combinator, which is in fact one reason why whitespace isn't "allowed" around the delimiters for pseudo-elements, pseudo-classes, attribute selectors, class selectors and ID selectors — because it has significance and therefore its presence alters the meaning of the selector.

:not(:empty) with space in CSS

You cant

(unfortunately)

The :empty selector is the only way in CSS of detecting content, and also proves positive for whitespace:

The :empty pseudo-class represents any element that has no children at
all. Only element nodes and text (including whitespace) are
considered. Comments or processing instructions do not affect whether
an element is considered empty or not.

Dont forget about the separation of concerns, HTML for content, CSS for styling and JS for functionality - as such, you either need to remove the whitespace from your HTML (content) or apply a class depending on its presence, or strip it using JS (functionality).

With that said, elements only containing whitespace should collapse by default, so long as the space in question isnt a non-breaking space

Demo Fiddle

difference between blank and empty pseudo-classes

The :blank pseudo-class builds upon the :empty pseudo-class. Like
:empty, :blank will select elements that contain nothing at all, or
contain only an HTML comment. But, :blank will also select elements
that include whitespace, which :empty will not
.

css-tricks :blank

Also, From the W3c Working Draft on selectors level 4:

The :blank pseudo-class is identical to the :empty pseudo-class,
except that it additionally excludes characters affected by whitespace
processing [CSS3TEXT] when determining whether an element is empty.

Example:

For example, the following element matches :blank, but not :empty,
because it contains at least one linebreak, and possibly other
whitespace:

<p> 
</p>

White space and selectors

For this cases I prefer using css selectors because of its minimalistic syntax:

response.css("p.text-nowrap.hidden-xs::text")

Also google chrome developer tools displays css selectors when you observing html code
This makes scraper development much easier
google developer tools

Hiding an element that contains only spaces using CSS

I don't think you can do it with pure CSS.

However with a little JavaScript you can do it.

var allParas = document.getElementsByTagName('p');
//filter by class name if desired...
for(var i=0;i<allParas.length;i++){
if(allParas[i].getElementsByTagName('*').length == 0){
allParas[i].style.display = 'none';
}
}

If you have access to jQuery it is a little easier to do the filtering with their built in selectors.

$('p.sitspagedesc').each(function(){
if($(this).children().length == 0){
$(this).hide();
}
});


Related Topics



Leave a reply



Submit