CSS writers are the blind swordsmen of web development: we pen declarations and throw them at HTML 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, PHP, 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.
Auckland | Papeete | Los Angeles | |
---|---|---|---|
Auckland | 2542 | 6518 | |
Papeete | 2542 | 4114 | |
Los Angeles | 6518 | 4114 |
The markup for the table is as follows (I’m using HTML5 shortcuts for speed):
<table>
<caption>Distances Between Cities On The Pacific Rim (miles)</caption>
<col><col><col><col>
<tr>
<th><th scope=col>Auckland<th scope=col>Papeete<th scope=col>Los Angeles
<tr>
<th scope=row>Auckland<td><td>2542<td>6518
<tr>
<th scope=row>Papeete<td>2542<td><td>4114
<tr>
<th scope=row>Los Angeles<td>6518<td>4114<td>
</table>
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>
</nav>
… 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:
<p>
Although such a tag with no carriage return between it and the next one would be:
<p><p>
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…
<p></p>
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.