Closed xiaochengh closed 2 weeks ago
Ahhh goodness, @xiaochengh I think you're correct that this would be the expected result. However, I agree with @josepharhar in the chrome bug that there are ways around this. As a dev, I'd probably reach for custom props or SASS mixins. However, these are not ideal but I don't see a solution to this that isn't more invasive. I know that @dbaron has a lot of historical knowledge on transforms so he may have some ideas.
Key thing that I think Open UI can do here is to understand how often this usecase will be hit by developers (eg: @jh3y has produced numerous demos with gorgeous animations and hasn't surfaced this issue). If we feel the issue is large enough we'll need to surface our recommendation to the CSSWG since they own this.
This would be the expected behavior as anchor positioning ignores CSS transforms. The only way around this would be to apply the same transforms to the list box (assuming they were translations).
Unfortunately, when it comes to say scaling up the button on :active
/:hover
, the developer would need to counter for that then compensate in the anchor position and apply any scaling to the list box. I don't think it's a use case that warrants changing how these APIs work. It's mainly something for people to be aware of. Workaround would be to use calc
with the anchor
function to compensate for any scaling. For example, if the button was scaled. You could then set top
with something along these lines anchor(bottom) + ((anchor(bottom) - anchor(top)) * var(--scaling))
(Or using anchor-size
).
I could imagine adding a mechanism to anchor positioning that allowed applying the transform taken from an anchor to the anchor-positioned element. I could imagine a mechanism to do this working roughly as follows (although there are many options here that all have different behavior):
I think we perhaps don't want step 3 above to reverse-apply and the reapply the transform between the common ancestor and the anchored element, though I'm not sure of this.
But I'm not particularly sure of this math; it probably requires testing some options and seeing if they do reasonable things, and seeing whether the above math gets the transform origin behavior correct.
I could imagine adding a mechanism to anchor positioning that allowed applying the transform taken from an anchor to the anchor-positioned element. I could imagine a mechanism to do this working roughly as follows (although there are many options here that all have different behavior):
@xiaochengh and @tabatkins what do you think of this proposal? For the <selectmenu>
use case, there are several things that would appear broken:
scale
example from the OP here. The listbox would need to have the same scale
applied, or it would look odd.<selectmenu>
has a transform: translate(-50%, -50%)
on it, the selectmenu popover will appear at the wrong spot. It'll become "detached" from the in-page element. I worry a lot about this one, since transform:translate
is a common centering solution.Hm, I'm not confident that this would actually work in the common case without thinking more about it; translates are fine, but scales and rotates are completely dependent on the transform origin, not to mention skews!
I worry a lot about this one, since transform:translate is a common centering solution.
It's only common because centering didn't previously exist in a reliable form. It now does, in the form of the alignment properties (justify/align-*
). We shouldn't design for the assumption of people using legacy hacks; we should only do something with this if there's non-hacky use-cases we want to cover.
Hm, I'm not confident that this would actually work in the common case without thinking more about it; translates are fine, but scales and rotates are completely dependent on the transform origin, not to mention skews!
Totally agree that the main thing to worry about is translates.
I worry a lot about this one, since transform:translate is a common centering solution.
It's only common because centering didn't previously exist in a reliable form. It now does, in the form of the alignment properties (
justify/align-*
). We shouldn't design for the assumption of people using legacy hacks; we should only do something with this if there's non-hacky use-cases we want to cover.
While I do agree this is a "legacy hack", I believe it's still quite commonly used. The use case I'm afraid of is a legacy site (using transform:translate
like this) that wants to upgrade from <select>
to <selectlist>
- things will break. Similarly, a site using transform:translate
and a 3rd party component library, and the library starts using <selectlist>
.
If it isn't possible to make this use case work, or making it work sacrifices something from the regular feature, then I agree we shouldn't support it. But if it's possible to support, I think we should try.
I think there likely is a reasonable way to get a reasonable set of the cases of not-just-translation transforms right, but it probably requires prototyping in JS to check the math and check which option does the right thing. (That is, it requires a good bit more work than my current opining in comments!)
I think perhaps the less clear question if we add a property to apply the transform from an anchor, is what the expected interaction is with transforms that are on elements between the anchored element and least-common-ancestor(anchored element, anchor element). I'm not sure there's a good answer to that, since I suspect there may be both use cases that would expect them to be ignored (or cancelled out) and use cases that would expect them to be honored (but compounded how with the transforms from the anchor element?) -- though maybe a good enough answer to that question is to specify some interaction that does reasonable things if there's only a transform in one of the two places -- and if you have transforms in both then you probably get something weird.
+1 to doing some JS prototyping first.
I think perhaps the less clear question if we add a property to apply the transform from an anchor, is what the expected interaction is with transforms that are on elements between the anchored element and least-common-ancestor(anchored element, anchor element).
We don't need to worry about this, because there can't be such elements.
The anchored element must be absolutely positioned, and its anchor must be in the containing block of the anchored element. Also, any transform will establish a containing block. As a result, the LCA is always the containing block, and there can't be any additional transforms between the LCA and the anchored element.
There hasn't been any discussion on this issue for a while, so we're marking it as stale. If you choose to kick off the discussion again, we'll remove the 'stale' label.
I could imagine adding a mechanism to anchor positioning that allowed applying the transform taken from an anchor to the anchor-positioned element.
In the sentiment of this comment, I agree that this seems like a general anchor positioning issue and not a selectmenu/selectlist/select issue. Not sure what to do about it though.
I think this should be solved by anchor positioning rather than being a select-specific behavior we add for appearance:base. I'll post about it in the crbug
(Originally filed as a Chrome bug)
If we add transform to a
<selectmenu>
, egselectmenu { transform: scale(1.5) }
, we probably expect every part of the selectmenu to be scaled. However, the listbox is not scaled. (See test case)This is because:
transform
is a non-inherited property, so the listbox's owntransform
value is still initial<selectmenu>
in the box treeAs a result, the listbox doesn't get any transform.
I don't see any easy solution. Adding UA style to the listbox (eg
selectmenu::part(listbox) { transform: inherit }
) doesn't fix it.