Open josepharhar opened 7 months ago
In particular what we're looking for here is a way whereby a new value of the appearance
property impacts the backing style sheet of the element. It's acceptable if this mechanism only works for HTML form controls.
@nt1m conceptualized this idea as a user agent at-rule, e.g.,
select {
@appearance-base {
border: thin solid ButtonBorder;
...
}
}
(Conceptually this needs to be something like an at-rule as you might need to style various states as well.)
I’ve tried implementing a few solutions to this and here are my thoughts:
We could have an internal pseudo-class which matches the select when it has a child in the new content model, which would be a button or datalist. This way we can adjust the UA styles based on the new DOM to get the new UA styles. I currently have this implemented in the chromium prototype here: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/resources/html.css;l=918-929;drc=df34b11bbe7a46c53c782a6d4a24145a4af05e10
Issues:
<button>
or <datalist>
content, you won’t get updated UA styles.After style recalc, chromium and webkit have a style adjuster which changes the computed style. We could look for appearance:bikeshed on a select element here and remove a few styles we don’t want, like border and background-color. I started a patch to implement this in chromium here: https://chromium-review.googlesource.com/c/chromium/src/+/5348242/2/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
Issues:
We could just leave the problematic UA styles in there and make the developer revert all of them when they apply appearance:bikeshed.
Issues:
We could use an HTML attribute instead of appearance:bikeshed to opt in to the new behavior and content model (similar to to the proposed switch attribute?). This attribute could be used in the UA stylesheet to change the styles as desired.
We could add an internal @ rule or internal pseudo-class to gate the UA styles based on appearance as desired.
Issues:
@emilio do you have any thoughts?
I'm not sure solution 5 would require two style passes. I think that depends on how it's implemented. If it's implemented in terms of solution 2 for instance, maybe not? Also, for solution 2 you can read out author styles and account for them. It's just a lot of work which is why some kind of novel mechanism is needed that abstract that so you don't have to implement "base style sheets" from scratch for each control.
I agree with @andruud that requiring two styling passes is a no-go. It's also cyclic, even though if you restrict the pseudo-class / at-rule to the UA sheet you can kinda cheat and assume that there's no cycle...
What styles do you plan to apply to <select>
on this case? <select>
already has default styles that are somewhat reasonable (borders etc) for appearance: none
.
We discussed this with @annevk and @mfreed7 in the context of <input type=checkbox switch>
too. My preference would be to not do this. Have the default styles be sane and either:
appearance: none
be the "stylable, uses a non-replaced box and thus has pseudo-elements and other goodies" behavior (we can do this for switch
, but likely not for <select>
).appearance: base
create a non-replaced box, and thus render child elements, have pseudo-elements etc. appearance: none
would still create a replaced box that wouldn't create renderers / layout objects for the pseudo-elements and thus would remain behaving as it is.This has no cycles and is trivialish to implement, but whether this is possible depends on the kind of styling differences that you want to have between base
and none
/ auto
.
cc @chrishtr and @zcorpan who were also in that conversation.
For the white-space: pre
issue that can probably be removed? Gecko at least doesn't have it unless I'm missing something.
Ah, I guess gecko has white-space: nowrap !important
. But we could make that part of the internal box styles for the none
/ auto
case.
@emilio While your suggestion does remove magic from style system, it does introduce a burden to the web developer to specify input::decoration
(or however the anonymous box will be targeted by the web dev), which I think is undesirable.
@nt1m you mean select::decoration
(or something)? And how so? You can use styles for the internal anonymous box when appearance isn't base
, and make base
give you a regular box.
Would the base styles for the input move to the anonymous box? Or would the anonymous box have a pseudo-element to target them (e.g. ::decoration) with the UA sheet styling that?
What kinds of differences do we want between none
and base
? Most controls with none
look reasonable (checkbox / radio being the exception).
My preference would be to keep the styles the same, and the difference would be which kind of box none
creates vs. base
(so that e.g. display: flex
works with appearance: base
and so on).
I reviewed all of the UA styles for <select>
as well as the ones desired for a stylable <select>
. It turns out that we don't need to change style on the <select>
element; we only need to style its child elements like the options, button or datalist. We can do that with new interoperable UA styles that always apply, even for existing usages of <select>
, since existing <select>
usage has no children that render via CSS.
Therefore "solution 3: leave the UA styles in there" will work fine and turns out to have no significant problem of poor ergonomics. And we can go with what Emilio suggested and all is well.
When the time comes to add stylability to other form controls, we can follow this pattern and just leave existing interoperable UA styles in place, and expect developers to add in their own customizations.
But that means we cannot for instance have consistent sizing and theming for appearance:base
controls, can we? Because whenever any of that would clash with none
it would not be okay? I thought the idea with base
was that we'd have a "web native" consistent look & feel across form controls.
But that means we cannot for instance have consistent sizing and theming for appearance:base controls, can we?
That’s correct. The user agent style sheet rules will have to be the same for all values of appearance
(though we do have some flexibility to choose the rules for children of the select element without compat risk).
Because whenever any of that would clash with none it would not be okay?
Right.
I thought the idea with base was that we'd have a "web native" consistent look & feel across form controls.
That was the original plan, but I concluded that it’s not implementable due to the circularity / double-style recalc / needing bespoke style engine hacks problems mentioned earlier.
I think that’s acceptable, because developers likely want to add their own customizations anyway in this mode, and it’s simple because there are only four CSS properties to override (border
, border-radius
, display
and background-color
).
Hi, I worked with @argyleink to explore how developers might style a checkbox, switch or range control on top of appearance:base
. The prototype assumes that the UA stylesheet for input
doesn’t change, but that rules for pseudo-element box tree children can be added as we define them (in particular, look at the @layer demo.base
cascade layer). It also assumes a rendering model where pseudo-element contents like checkbox glyph and range are replaceable slot-style and are descendants in the layout tree.
Note: <select>
should be fine also, based on another analysis @josepharhar and I did of the UA style sheet for that element that he referred to earlier. There are also various <selectlist>
examples (from a previous design) that demonstrate the concept.
Again, these are not API proposals, but just data to show styling can work, to validate that the current design path regarding CSS is feasible for additional form controls.
In the prototypes you'll find markup like:
<base-checkbox tabindex=0>
<base-mark class="base">
<svg viewBox="0 0 512 512"><path d="M416 128L192 384l-96-96"/></svg>
</base-mark>
</base-checkbox>
The intent of the custom elements is to help articulate an end result where in the box tree the marker is under the input:
Input
Marker
<developer content>
The range input needs more parts than just a custom checkmark; the shape of it is like this (modeled very much after what has already been shipped):
<base-range tabindex=0>
<base-range-container>
<base-track></base-track>
<base-progress></base-progress>
<base-thumb></base-thumb>
</base-range-container>
</base-range>
When appearance: base
is used on a range, the resulting box tree looks something like this:
Input
Group
Track
<developer content>
Progress
<developer content>
Thumb
<developer content>
I don't really understand what I'm looking at. Are you suggesting that appearance:base
would change the contents of the box/shadow tree? I thought @emilio was opposed to that?
How does it end up being different from appearance:none
?
This still seems like a far cry from the appearance:base
we envisioned, that would give web developers a cross-browser pre-styled control that would satisfy all relevant UX, a11y, and i18n criteria.
I would find it useful if we could find another hour to discuss this in person again. Happy to organize that if that's agreeable.
@annevk not necessarily. The box tree might change without the shadow tree having to change.
E.g. the shadow tree could be the same, but appearance: auto
might create a replaced box (which won't render the children). It's the same as <iframe>
fallback content or so.
@emilio fair, but that doesn't really address how it's different from appearance:none
? Is that idea that sometimes we expose pseudo-elements in appearance:none
and sometimes not?
appearance: none
has some compat requirements for e.g., <select>
that might prevent it from just creating boxes for its children regularly. I'd expect appearance: none
for select to keep creating a replaced box, but maybe we can get away without that? Not sure.
It hadn't occurred to me before, but we could do something like light-dark()
to support this (thanks @lilles!). We could give the UA properties that we care about an internal CSS function which evaluates to one thing for appearance:auto/none, and a different one for appearance:base/base-select.
As I've implemented in chromium, it looks like this for background-color specifically:
select {
background-color: -internal-appearance-auto-base-select(Field, transparent);
}
This required the appearance
property to be computed before background-color
, but I was able to enforce this in chromium by setting the priority of appearance to a higher value than background-color.
I don't know if the per-property priority is something that exists in csswg specs, and I'm not sure if the particular form of this function is what we would want to spec either, but from my point of view this solves the issue.
I don't know if the per-property priority is something that exists in csswg specs
It doesn't, we just generally ensure that there aren't dependency loops and assume UAs will handle the rest themselves.
Elevating the priority for appearance makes sense for how Chrome handles these things. And that function proposal (so long as it remains internal, of course) looks reasonable to me.
Here is a proposed resolution: "Changing UA styles based on the computed value of the appearance property is acceptable"
The CSS Working Group just discussed [css-ui] Changing UA styles based on the computed value of the appearance property
, and agreed to the following:
RESOLVED: user agent styles can depend on appearance:base. Aim for eventual interoperability across all values of the property.
I'm working on improvements to the
<select>
element (whatwg thread here), and I came across an issue while implementing a prototype of the Apple-supported behavior of switching to a new rendering mode based on the value of the appearance property.The select element has several UA style rules which we don't want in the new rendering mode, such as white-space:pre, which makes all of the options in the popup have a bunch of line breaks rendered in my examples.
I tried adding an internal pseudo-selector which matches when the element has the new appearance value, but I found that it took two style updates to get the final style, which @andruud described as a "non-starter".
@annevk suggested that I should ask here to see if there is a way that we can make this work.
Also, if there are any previous discussions about the appearance property that are related to this, I would appreciate links to them.
cc @nt1m