w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.5k stars 661 forks source link

[css-ui] Should `::picker(select)` match `:popover-open`? #10775

Open josepharhar opened 2 months ago

josepharhar commented 2 months ago

We resolved to make ::picker(select) be a part-like pseudo-element here: https://github.com/w3c/csswg-drafts/issues/10758

However, there were questions about whether we should make it match :popover-open.

I believe that since ::picker(select) is a part-like pseudo-element, it should match :popover-open.

Here are some reasons I understood were brought up that it shouldn't match :popover-open with my counterarguments:

nt1m commented 2 months ago

Allowing :popover-open to be matched reveals internal implementation details of <select>.

In general the less API surface there is, the less problems are likely going to come up in the future. Web APIs should be designed to last. We could decide that popover is no longer the right paradigm for pickers in the future. Should we be stuck with supporting :popover-open then?

There shouldn't be more than one way to detect this state in CSS, so we should use select:open instead of ::picker(select):popover-open.

Quoting @fantasai: We want form controls to act like they’re built into the language, not built out of author facilities in the language; and that their full functionality can be implemented without those author facilities.

:open / :closed covers the different use cases fine. Should developers care that this is a popover honestly? I think what really matters for the purposes of styling and animation is that it's an element in the top layer. It doesn't really matter if it's a popover or a dialog.

yisibl commented 2 months ago

As a developer, for me I don't care if it's a popover. It would be much simpler and less expensive to learn to standardize on one :open for all scenarios.

Also, even if both selectors are supported, the CSS compressor will be compressed to the shorter :open in the future, and from that perspective, :popover-open will be used by fewer people in the future.

annevk commented 2 months ago

I think requiring :popover-open to match would very much go against our earlier decision not to reuse ::part(). Whether or not ::picker(select) points to an HTML element with a popover attribute set is an implementation detail. If implementations want to implement ::picker(select) without an element node they should be allowed to do that. ::picker(select) needs to behave like popovers in a number of respects, but it shouldn't be required to use the exact same mechanism underneath.

Now I suppose we could update the :popover-open requirements to say that ::picker(select) also needs to be matched, but that seems kinda pointless to me given that we already plan to add :open to select elements.

josepharhar commented 2 months ago

The draft HTML spec that I've written explicitly says that ::picker(select) maps to an element which has the popover attribute, and we resolved on making it a part-like pseudo element. I still don't see how adding a special case to not parse :popover-open is helpful, but since its functionally the same as :open for popover animations and therefore doesn't limit what authors can do, and there seems to be significant pushback, I'll let it go and add a console message in this case to help point developers to the accepted syntax.

Proposed resolution: add a special case to not parse :popover-open for the ::picker(select) pseudo-element.

tabatkins commented 2 months ago

While we resolved against using ::part() itself, we did resolve to make it a "part-like pseudo-element", and that means it acts like ::part() but is just spelled differently. Notably, ::part() does expose implementation details like what pseudo-classes and pseudo-elements are usable on the element, and this is intentional. (As opposed to the other pseudo-elements, which only allow a limited subset of pseudo classes/elements after them.)

I don't think we should try to diverge ::picker() from the agreed-upon concept of part-like pseudos.

nt1m commented 2 months ago

I don't think we should be locking ourselves in unnecessarily by exposing things that are not useful and may potentially cause a compat hazard later if something needs to change. While popover may seem like an appropriate concept to re-use now, it might not be the case later.

Fwiw, I'm also OK with making :popover-open not match instead of not parse (there's a subtle difference there), if that preserves the technical purity a bit more.

dbaron commented 2 months ago

I agree that we should stick to the concept of part-like pseudo-elements.

If we add an exception here, how many other exceptions will we add? How much working group time and implementor time will be spent implementing those exceptions, that could have been used for something else? And how much author confusion will result?

I really do think that what we're trying to do here is to provide an author-facing model for complex built-in widgets that exposes to developers that these widgets are composed of more basic pieces of web technology. This has been the plan for a long time (>20 years) because it seemed like the only practical way to standardize the stylability of complex widgets, and I still think this is the case. I thought that the conclusion in https://github.com/w3c/csswg-drafts/issues/9951#issuecomment-1997897418 agreed with this concept but concluded that we would not use the name ::part() because it was for author-built components and for standardized components that were built in to the Web platform.

annevk commented 2 months ago

I don't think I argued against making it a part-like pseudo-element? Not sure why that is being revisited.

I argued against exposing the fact that ::picker() matches a particular type of element. I think the tradeoff is between forever enshrining that this needs to act as if there was an HTML element with a popover attribute set underneath versus keeping it more general and only requiring more "obvious" pseudo classes to match, such as :hover. Who knows, we might introduce a better suited element such as <popup> at one point which would not match :popover-open. In order to reuse it here we'd have to add special cases at that point.

The other argument against it matching is that it introduces redundant API surface. This is slightly weaker, but whenever we don't have to, I'd definitely prefer not introducing redundant ways to do the same thing, especially if the redundant way is significantly more verbose and addresses fewer scenarios.

tabatkins commented 1 month ago

The markup structure of a base ::picker() is going to be precisely standardized, I thought. That's required, in practice, for it to be predictably styleable, which is the point of the base feature in the first place. Any changes we make to the markup structure are going to be constrained by compat, or gated behind a new appearance keyword if they're too radical.

Looking back at the spec for part-like pseudos, I see that it doesn't actually carry over the bit of [::part()'s definition](https://drafts.csswg.org/css-shadow-parts/#part:~:text=The%20%3A%3Apart()%20pseudo%2Delement%20can%20take%20additional%20pseudo%2Dclasses%20after%20it) that allows arbitrary pseudo-classes to be used on it, but that was the intention. I'll look into getting that fixed.

mfreed7 commented 1 month ago

The markup structure of a base ::picker() is going to be precisely standardized, I thought. That's required, in practice, for it to be predictably styleable, which is the point of the base feature in the first place. Any changes we make to the markup structure are going to be constrained by compat, or gated behind a new appearance keyword if they're too radical.

This was my thought as well. It feels very confusing to developers to see that the <select> is using a popover (per spec), but have :popover-open not match (or worse, not parse!) on that popover.

annevk commented 1 month ago

I see it a bit differently. Internal shadow trees allow us to more precisely define the observable behavior of certain built-in elements and give us a handful of shortcuts in defining such behavior, but:

  1. We still get to decide as to what the overall API should be and what details of the shadow tree we wish to reveal and expose and which we hold back for future enhancements.
  2. Implementations are free to implement it differently as long as the observable behavior is the same.
css-meeting-bot commented 1 month ago

The CSS Working Group just discussed [css-ui] Should `::picker(select)` match `:popover-open`?, and agreed to the following:

The full IRC log of that discussion <chrishtr> jarhar: this is a topic that was spun out of ::picker. There is disagreement about whether :popover-open should match. We already resolved that ::picker is a part-like pseudo element.
<jarhar> q?
<una> q+
<chrishtr> jarhar: there is the question of whether it should match :popover-element. I and some others think it should because that's the default for part-like pseudos. Others don't like it because it would reveal internal details
<masonf> q+ simon
<gregwhitworth> ack una
<chrishtr> una: clarifying question: would this match both open and popover-open, or just popover-open?
<chrishtr> jarhar: there is no contention about :open, discussion is just for :popover-open.
<chrishtr> una: so with your preferred resolution it'd match both?
<chrishtr> masonf: yes
<chrishtr> una: ok I agree with that, just checking
<chrishtr> dbaron: select matches open, and picker matches popover-open
<chrishtr> una: if you have appearance:base-select for both the in-page and picker, then select:open would be the same as picker:poover-open
<zcorpan> ack simon
<chrishtr> una: if you only have appearance: base on the select and not the picker, then you can only match select:open because the picker doesn't exist
<chrishtr> fantasai: seems like it has to exist
<chrishtr> annevk: exists but doesn't match because it isn't styleable
<chrishtr> annevk: isn't that the case for other pseudo-elements anyway?
<chrishtr> fantasai: exists but not styleable
<dbaron> (I'm not actually 100% sure that ::picker(select):popover-open doesn't work when ::picker(select) is appearance:auto... although I *think* that's the case
<chrishtr> fantasai: if we allow popover-open to apply to the picker then it won't apply if not in base mode?
<una> q+
<chrishtr> jarhar: the picker element exists but in auto mode it can't be opened as a popover because it never opens
<fantasai> ::picker(selecT) { appearance: base; } ::picker(select):popover-open { appearance: auto; }
<chrishtr> fantasai: what about applying appearance:auto if :popover-open, what will that do?
<chrishtr> annevk: would be a loop?
<chrishtr> masonf: which picker you open depends on timing. If it's already open then it wouldn't close?
<chrishtr> annevk: normally in CSS if the computed value changes then what you see changes
<chrishtr> masonf: if so then there would need to be some code to handle it
<gregwhitworth> ack una
<dbaron> (I think this is sort of exposing a problem with making `appearance` apply separately to `::picker(select)`... it probably normally would have been restricted.)
<chrishtr> una: maybe this is a difference between part-like and regular pseudo elements?
<chrishtr> fantasai: this was relaxed before for pseudos
<chrishtr> q+
<chrishtr> una: second question: just updated my demos when I updated them to the new syntax. e.g. focus-visible didn't apply any more. Wanted to see if this ok. Also is there an issue with specificity?
<zcorpan> Demo for ::before:hover (seems like this is not implemented) https://software.hixie.ch/utilities/js/live-dom-viewer/saved/13060
<gregwhitworth> ack chrishtr
<fantasai> select:open ::picker() vs select ::picker():popover-open - same specificity
<chrishtr> fantasai: specificity would be the same
<gregwhitworth> chrishtr: wanted to bring us back, popover: open question jarhar originally raised
<gregwhitworth> masonf: the issue being discussed is their unique capabilities for this scenario
<jarhar> proposed resolution: don't create a special exception to not parse :popover-open on ::picker(select)
<masonf> +1
<una> +1
<chrishtr> +1
<dbaron> +1
<zcorpan> +1
<emilio> +1
<sanketj_> +1
<gregwhitworth> RESOLVED: don't create a special exception to not parse :popover-open on ::picker(select)
<gregwhitworth> Zakim, end meeting
ByteEater-pl commented 1 month ago

Maybe it should be contingent on the value of appearance, so that in the future, when an alternative, possibly better rendering of select is implemented without this part, authors can choose. This opens, it seems to me, a path to the desired by many commenters forward compatibility. (But carves in stone the currently planned variant with the part, so that, even if one day considered legacy, implementations will have to continue supporting it.)

In general, each model of some control type with some innards exposed would need its own value of appearance. And if a need arises, multiple can exist for the same control type.

And two values of apperarance would always be available. Namely, none, which gives an element no special rendering or parts, and default (auto or base?) with no exposed parts but with possibly some special implementation-dependent rendering (satisfying some quite general constraints) and a limited set of applicable CSS properties.