Cet article est également disponible en français

writers are the blind swordsmen of web development: we pen declarations and throw them at documents hoping that something might stick, but rarely are we aware of the specific content of a selected element: the question of how many words are in a paragraph, or if it contains any words at all, has traditionally been the responsibility of JavaScript, , and other languages.

Very often server-side languages will be employed to fire dynamic content into HTML containers on a page. When such an operation fails, front-end developers deserve equal time to address the issue: rather than trying to code around a load problem using only JavaScript and PHP, we can add CSS to style the empty containers.

Treating the Mystery of the Empty Cell

Frequently tables are filled with dynamic data, but some cells in the table may have missing information. Usually, these cells are just left blank, but you might want to emphasize their lack of content in other ways.

A good example might be a table that shows the distances between cities. Naturally, there will be no mileage information between a city and itself, creating a series of empty cells.

Distances Between Cities On The Pacific Rim (miles)
AucklandPapeeteLos Angeles
Los Angeles65184114

The markup for the table is as follows (I’m using HTML5 shortcuts for speed):

	<caption>Distances Between Cities On The Pacific Rim (miles)</caption>
		<th><th scope=col>Auckland<th scope=col>Papeete<th scope=col>Los Angeles
		<th scope=row>Auckland<td><td>2542<td>6518
		<th scope=row>Papeete<td>2542<td><td>4114
		<th scope=row>Los Angeles<td>6518<td>4114<td>

This is a good use-case for :empty as the vacant cells must be included in order for the table to be valid and present well.  With :empty, targeting the cells that lack content is easy:

td:empty { background: #777; }

Note the structure of the code at the very end of the table, with the closing </table> tag right next to the last, empty <td> element. If that was not the case, the sole <td> tag would be treated as being “open” and not empty. (An alternative approach would be an opening and closing <td></td> with no space between them).

While odd, it should also be noted that you can combine the :empty and :not selectors to style cells that are filled:

td:not(:empty) { /* styles for filled cells */ }

This would be an unusual approach, as our assumption is that the majority of cells have content and can be addressed with a simple td selector, but it is still a valid approach in CSS.

Rehabilitating The Missing Link

Navigation for a site is often dynamically generated, sometimes incompletely. It’s possible to have space reserved for a link that never appears, or does so only fitfully. While this usually implies that your backend developers need to do more work, there’s a simple CSS solution that will make site navigation appear less like a gap-toothed smile in the interim:

nav[role="navigation"] a:empty { display: none; pointer-events: none; }

This means that a link with an href attribute value but no content will not be rendered in the browser. So taking this output HTML:

<nav role="navigation">
	<a href="index.html">Home</a>
	<a href="contact.html">Contact</a>
	<a href="tools.html">Tools</a>
	<a href="classes.html"></a>

… and adding the CSS above, will result in the last, empty tag not appearing. (In this case pointer-events is somewhat redundant, as the link won’t appear at all, and can’t be clicked in any case, but it’s a useful backup technique).

:empty Exceptions

Note that whitespace between an opening and closing tag counts as character information, as do any tags inside the targeted element. So the following is not considered an empty element:

<a href="classes.html"> </a>

Neither is this:

<a href="classes.html"><span></span></a>

As mentioned above, tags that are not closed, even if doing so is optional in HTML, do not count as empty, even if they have no content. A single paragraph is “open”, and therefore not empty:


Although such a tag with no carriage return between it and the next one would be:


In the example above, the first paragraph would be empty, but the second (assuming nothing else came immediately after it) would not be.

“Self-closed” elements are counted as being empty: <br>, horizontal rules, <img>, etc will respond to :empty.

Elements are counted as being empty if comments are their sole content:

<p><!--this paragraph is empty --></p>

Using :empty as a visual QA test for code

Inevitably, some developers get lazy. “Hey, I need more space under this element. I know, I’ll just add an empty paragraph".

<p>Some actual content…

Or, even worse, a <br> tag. This empty, “filler" markup gets in the way of well-written CSS, while being notoriously difficult to track down. We can use :empty as a quick visual check of pages for vestigial markup:

*:empty, br { border: 2px solid red; }

Browser support & conclusion

:empty has very good support: every modern browser, including IE9+, recognizes the selector.

There are many more possibilities for :empty: you’ll see one next month, in the redesign of this blog.

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.