Categories Programming & Tech

Should We Even Have :closed? | CSS-Tricks

For the past few months, I’ve been writing a lot of entries on pseudo-selectors in CSS, like::picker()or::checkmark. And, in the process, I noticed I tend to use the:openpseudo-selector a lot in my examples — and in my work in general.

Borrowing words from the fine author of the:open entry in the Almanac:

The CSS:openpseudo-selector targets elements that support open and closed states — such as the

andelements — and selects them in theiropen state.

So, given this:

details:open {
  background: lightblue;
  color: darkred;
}

We expect that the

element gets a light blue background and dark red text when it is in an open state (everywhere but Safari at the time I’m writing this):

But what if we want to select the “closed”state instead? That’s what we have the:closedpseudo-class for, right? It’ssupposedto match an element’s closed state. I say,supposedbecause it’s not specced yet.

But does it need to be specced at all? I only ask because we can still target an element’s closed state without it using :not():

/* When details is _not_ open, but closed */
details:not(:open) {
  /* ... */
}

So, again: do we really need a:closedpseudo-class? The answer may surprise you! (Just kidding, this isn’t that sort of article…)

Some background

Talks surrounding:openstarted in May 2022 whenMason Freedraisedthe issueof adding:open(which was also considered being named:top-layer at the time) to target elements in the top layer (like popups):

Today, the OpenUI WC similarlyresolvedto add a:top-layerpseudo class that should apply to (at least) elements using thePopup APIwhich are currently in the top layer. The intention for the naming and behavior, though, was that this pseudo class should also be general purpose. It should match any type of element in the top layer, including modal, fullscreen elements, and::backdroppseudo elements.

This sparked discourse on whether the name of the pseudo-element targeting the top layer of any type of element (e.g., popups, pickers, etc.) should either be:openor:top-layer. I, for one, was thrilled when theCSSWG eventually decided on :openin August 2022. The name makes a lot more sense to me because “open” assumes something in the top layer.

To :close or :not(:open)?

Hold on, though! In September that same year,Mason asked whether or not we should have something like a:closedpseudo-class to accompany :open. That way, we can match elements in their “closed” states just as we can their “open” states. That makes a lot of sense, t least on the surface. Tab Atkinschimed in:

I love this definition, as I think it captures a concept of “openness” that lines up with what most developers think “open” means. I also think it makes it relatively straightforward for HTML to connect it to specific elements.

What do folks think?

Should we also talk about adding the corresponding:closedpseudo class? That would avoid the problem that:not(:open)can match anything, including things that don’t open or close.

And guess what? Everyone seemed to agree. Why? Because it made sense at the time. I mean, since we have a pseudo-class that targets elements in their:openstate, surely it makes sense to have:closedto target elements in their closed states, right? Right??

No. There’s actually an issue with that line of reasoning. Joey Arharmade acomment about itin October that same year:

I opened a new issue about:closedbecause this doesn’t have consensus yet (#11039).

Wait, what happened to consensus? It’s the same question I raised at the top of this post. According toLuke Warlow:

Making:closedmatch things that can never be open feels odd. And would essentially make it:not(:open)in which case do we even need:closed? Like we don’t have a:popover-closedbecause it’s the inverse of:popover-open.

There is no :closed… for now

Fast forward one more month to November 2024. A consensus was made to start out with just:openandremove:closedfor the time being.

Dang. Nevertheless, according toWHATWGandCSSWG, that decision could change in the future. In fact, Bramus dropped a useful note in there just a month before WHATWG made the decision:

Just dropping this as an FYI::read-onlyis defined as:not(:read-write), andthat shipped.

Which do you find easier to understand?

Personally, I’m okay with:closed— or even using:not(:open) — so far as it works. In fact, I went ahead swapped :closed for :not(:open) in my ::checkmark and::picker() examples. That’s why they are they way they are today.

But! If you were to ask me which one comes easier to me on a typical day, I think I would say :closed. It’s easier for to think in literal terms than negated statements.

What do you think, though? Would you prefer having:closedor just leaving it as:not(:open)?

If you’re like me and you love following discussions like this, you can always head over toCSSWG drafts on GitHub to watch or participate in the fun.