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:
: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:
outline: 1px dashed red;
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
textareas 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?