Running on :empty
Published 17 years, 9 months past
While kicking around some ideas at the CSS workshop I led in London, I ran into some interesting problems with :empty
. If you’re not up on what that one does, it’s a way of selecting elements that have no children, including text. To quote the formal definition:
The
:empty
pseudo-class represents an element that has no children at all. In terms of the DOM, only element nodes and text nodes (including CDATA nodes and entity references) whose data has a non-zero length must be considered as affecting emptiness; comments, PIs, and other nodes must not affect whether an element is considered empty or not.
So kindly consider:
*:empty { padding: 0.25em; outline: 1px dashed red; background: yellow; }
We (re)discovered something very strange right there in the workshop: given the preceding rule, Firefox applies it to the body
element—which is, quite clearly, not empty. You can check out the fun on my bare *:empty
test page. From there, we realized that if you prepend a body
to the selector, yielding body *:empty
, the problem vanishes, as you might expect.
As it turns out, this is a known bug in Gecko. It’s been known for about 18 months, in fact. So that’s why I was confused by Firefox’s behavior.
The other problem is that :empty
in Firefox matches img
elements, whether or not they cause an image to successfully load. You can see this happen on the same test page. While it’s true that img
is an empty element, it’s still bringing in content, so from a common-sense point of view it seems that :empty
ought not to match.
In re-reading the description from the specification, though, I can’t justify my common-sense interpretation—an img
element has neither element nodes nor text nodes, so far as I’m aware. The same is true for form inputs, even text inputs that have pre-filled value text; but not for textarea
s that have pre-filled content text. But then br
elements should also be selected by this rule, and they apparently don’t get matched at all, as the test page shows. Bwuh?
Well, maybe it’s a bug. What concerns me here is that the definition of :empty
basically requires that things like images and inputs always be selected, which strikes me as kind of useless. After all, if I wanted to select all images, I’d write img
into my selector; ditto input
for inputs.
My thinking is that the description should change to state that application of :empty
is restricted to non-replaced elements. Alternatively, it could be redefined to only apply non-replaced elements and to empty replaced elements that don’t either cause something to load or have values associated with them.
Which seems a better solution to you, and why? Or, if you see a better approach than either of those, what is it?