meyerweb.com

Skip to: site navigation/presentation
Skip to: Thoughts From Eric

Running on :empty

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

23 Responses»

    • #1
    • Comment
    • Fri 17 Aug 2007
    • 1259
    AlastairC wrote in to say...

    Empty seems to be quite a confusing term here, I’d rather see it separated into a couple of more useful things. One would be a way of selecting text-only nodes.

    • #2
    • Comment
    • Fri 17 Aug 2007
    • 1418
    thacker wrote in to say...

    Meyer–

    Playing the devil’s advocate, since it appears the pseudo-class empty is not supported by Opera or IE, why worry about it, with arguments of principle aside and providing that I am not overlooking some practical uses of it.

    On theoretical purposes, possibly, the latter definition you provided.

    Logic: I am a guy and at the moment, more is better.

    • #3
    • Comment
    • Fri 17 Aug 2007
    • 1428
    thacker wrote in to say...

    Did I just stick my foot in my mouth? Your test example doesn’t work in Opera or IE. I have no direct knowledge whether :empty works in Opera or IE. Just ran your example through both to try to gain better understanding of a CSS element of which I was not familiar until your post.

    • #4
    • Comment
    • Fri 17 Aug 2007
    • 1524
    Ben Kimball wrote in to say...

    I don’t have anything like your depth of experience here, but it seems to me that what I’d like is to select any element which could have children, based on the DTD, but doesn’t. I don’t think (haven’t actually checked) that a well-formed img element can have children, so I wouldn’t expect it to be selected. Ditto img, hr, and anything else defined as <!ELEMENT foo EMPTY>.

    This would mean that a textarea with pre-defined content would be selected, while an input with pre-defined content wouldn’t be. That’s not ideal, I guess.

    • #5
    • Comment
    • Fri 17 Aug 2007
    • 1618
    Jeff Smick wrote in to say...

    Elements defined <!ELEMENT _ EMPTY> shouldn’t be selected and I’d add textarea to that to keep it in line with the other form elements.

    It seems to me that textarea is implicitly an empty form element. Given that though, putting textarea on the list of non-selected elements begs the question: should option elements also be included considering, like textarea, they also can only contain #PCDATA.

    Perhaps it’s just easier to only include elements defined EMPTY on the “do not select” list.

    Great question Eric.

    • #6
    • Comment
    • Fri 17 Aug 2007
    • 1619
    fantasai wrote in to say...

    a) IIRC Mozilla also has known bugs with styling <br>, so it’s probably not a very good example. Form controls have a number of (mostly intended) styling restrictions as well, so you’d have to design your test case carefully for those.

    b) In CSS3 whether an element is a replaced element or not will depend on the value of its ‘content’ property. To avoid a circular dependency, then, a selector that differentiates between replaced and non-replaced content can’t be defined.

    Anyway, what would be your use case for a *:empty selector? I can’t think of any cases where you wouldn’t want a tag/class/id selector in there anyway.

    • #7
    • Comment
    • Fri 17 Aug 2007
    • 1723
    Sean Hogan wrote in to say...

    Styling for content that isn’t there is kind of counter-intuitive to me.
    Can I ask what the idea was that prompted this discovery?

    • #8
    • Comment
    • Fri 17 Aug 2007
    • 1827
    Ralph wrote in to say...

    While the questioning is interesting, is perfectly understandable the fact that it selects img, input & other (by definition) empty elements, after all, they are empty.

    This may have no sense to you if you take the :empty statement outside of the DOM context, but at the same time is perfectly logical inside it (the body bug, of course, it’s just that: a bug).

    I do understand, however, your logic, but it reminds me of the problems measuring accessibility, which is subjective but measured by a computer. In this case I see it as the other way around: a computer tool for DOM manipulation (XPath) used in a subjective way :).

    • #9
    • Comment
    • Fri 17 Aug 2007
    • 1831
    Ralph wrote in to say...

    I forgot to summarize…

    This is a problem of context. The :empty statement applies to empty elements. As far as I know it doesn’t take into consideration their attributes, and frankly I see no reason to do so, even more since you can reference them directly with [attribute].

    • #10
    • Comment
    • Fri 17 Aug 2007
    • 2329
    Dana wrote in to say...

    It seems like this is a bit open to interpretation. To me, empty means “no children”. So, if I want to find, say, all empty p elements, I could use p:empty for my selector. In my mind, it would make sense then for *:empty to apply to textarea elements if there is not text in them. If there is text, then they wouldn’t be selected.

    I also tend to agree with Ralph that the attributes wouldn’t be considered, therefore img elements would always be selected, as they have no child nodes.

    Perhaps a new pseudo-class is needed for the situation you bring up where an img element’s data successfully loads or not. Something like nocontent? I guess there would be some overlap between empty and something like that, though.

    • #11
    • Comment
    • Sat 18 Aug 2007
    • 0549
    Sebastian Redl wrote in to say...

    Here’s another little weirdness in the spec:

    <object …></object> is matched.
    <object …><param name=”foo” value=”bar”/></object> is not.

    • #12
    • Comment
    • Sat 18 Aug 2007
    • 1212
    Nils Maier wrote in to say...

    The DOM-Inspector tells me that the box you see is not body but the empty node from the head.
    Or am I missing something?

    • #13
    • Comment
    • Sat 18 Aug 2007
    • 1214
    Nils Maier wrote in to say...

    Err, “the empty link-Node”.
    (Should have known that the blogsoft would filter it completely when written as tag)

    • #14
    • Comment
    • Sat 18 Aug 2007
    • 1857
    Eric Meyer wrote in to say...

    I’d actually expect that, Sebastian, since in the first case object has no child nodes, and in the second case it does. On the other hand, if the param isn’t selected, then that’s either total spec weirdness or a browser bug. To test it, you’d have to make sure the display of both object and param was something other than none.

    I think you are missing something, Nils. In the first part of the post, I’m talking about the body being inappropriately selected, as documented in the Bugzilla entry. In the second part, I’m talking about selection of empty elements that are DOM-empty but not render-empty, like images and inputs and such. I didn’t say anything about that appearance of the top-most tiny box on the test page, which is indeed the link element and (given that we accept HTML-empty elements are selected by :empty) should be seen, given the rest of the styles.

    • #15
    • Comment
    • Sun 19 Aug 2007
    • 2218
    Ralph wrote in to say...

    Interesting… I wonder if we should see the link element. Why would head children be rendered at all? What sense does it have? I even find the br element not being shown (in the test page) has more sense, I mean, this is a replaced element, isn’t?. If that’s so, then most of CSS rules don’t apply at all —though I still wonder just what kind of element br is and how is it implemented across browsers.

    This leads me to another issue: should we be grateful with browser vendors that they give us some little freedom there (with replaced elements)? I mean, do you think this is positive at all? —If you ask me, I think it is, I tend to alter the border and background of input‘s, for instance. What’s your opinion?

    • #16
    • Comment
    • Sun 19 Aug 2007
    • 2301
    Eric Meyer wrote in to say...

    Ralph, the head children are being rendered because I opened up the head in order to display the embedded style element in the upper right corner there—and, by the by, to see if empty head descendants like link would be matched.

    As for allowing us to style replaced elements, I’m ambivalent, for many and sundry reasons.

    • #17
    • Comment
    • Mon 20 Aug 2007
    • 0349
    Mats Lindblad wrote in to say...

    What happens to ?

    I agree that logic should rule what is affected and not.
    Meaning that elements that render content on the page are NOT :empty, such as images and :s.

    :empty elements are what the validator warns you about, I.E. elements that, possibly, contains only white-space nodes, comments or PI.
    Not what is referred to as EMPTY elements in the spec.

    • #18
    • Comment
    • Mon 20 Aug 2007
    • 1228
    Rick wrote in to say...

    I just found a name for my nascent web design business:

    head:empty

    • #19
    • Comment
    • Mon 20 Aug 2007
    • 2144
    Eric Everman wrote in to say...

    :empty seems incompatible with html/xhtml, since whitespace is supposed to be ignored. For instance, if the html/xhtml spec says that:

    <p></p>
    and
    <p> [spaces] </p>

    are supposed to be equivalent, it seems to me that the browser could legitimately collapse the distinction b/t the two in the DOM model before applying the CSS styling. …Or I could be wrong on that – perhaps the spec says that one space is the same as twenty spaces, but any number of spaces is different then zero spaces…

    • #20
    • Comment
    • Tue 21 Aug 2007
    • 1245
    Christopher wrote in to say...

    Would there be issue with any element that is self closing not being considered ‘empty’? I see no benefit to targeting ‘br’ or ‘hr’ with :empty.

    As for ‘img’ and ‘input’, it seems to me that an attribute selector checking their ‘src’ and ‘value’ properties respectively would suffice when you wanted to see if they were truly ‘empty’.

    This pseudo-class seems primarily targeted at paragraphs and divs without text, as I see little in the way of other practical uses for it (perhaps anchors?).

    • #21
    • Comment
    • Fri 24 Aug 2007
    • 1711
    Carter wrote in to say...

    I’ve just run into a situation where :empty not applying to input elements definitely seemed to go against common sense. I’m using javascript to find the first empty input element in a form and set focus to it. As Christopher mentioned, the attribute selector works just peachy instead–

    Here’s the selector string I’m using (with jQuery)

    $("[@value='']:input:visible:enabled:first")

    I agree that using on [@value=''] or [@src=''] makes more sense then the common-sense approach to :empty, although initially I was also a little thrown.

    • #22
    • Comment
    • Fri 24 Aug 2007
    • 2121
    Will Kessel wrote in to say...

    So: you led me to playing around with this :empty stuff, eh? Just because I have a new job, and now I have to play catch-up… grrr….. ;-)

    Until now, I have completely ignored the :empty pseudo-element. A quick glance at the spec tells me that this might be a fairly handy feature for someone who has to populate a table with some dynamically-generated (tabular, of course) data, and wishes to highlight empty cells for whatever reason.

    So I did a quick-and-dirty experiment. (Granted, the contents aren’t dynamically generated, but for this experiment, it matters little.)

    Firefox 2.0.0.6/Mac handled this one with ease, albeit with a couple of minor rendering glitches; Safari 2.0.4 (419.3) blew it to pieces, styling every td as empty instead of just the empty ones. And the value of the very last cell, the number 12, is not within a p tag like the rest of the cells…

    Veddy intrestink.

    • #23
    • Comment
    • Thu 13 Sep 2007
    • 0531
    Robin wrote in to say...

    For the specific case of empty tables cells there’s a special rule already in CSS2.1: empty-cells:show|hide. Although, yes, :empty is more flexible.

Leave a Comment

Line and paragraph breaks automatic, e-mail address required but never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



Remember to encode character entities if you're posting markup examples! Management reserves the right to edit or remove any comment—especially those that are abusive, irrelevant to the topic at hand, or made by anonymous posters—although honestly, most edits are a matter of fixing mangled markup. Thus the note about encoding your entities. If you're satisfied with what you've written, then go ahead...


August 2007
SMTWTFS
July September
 1234
567891011
12131415161718
19202122232425
262728293031  

Sidestep

Feeds

Extras