-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove top layer definitions, now that CSS Position 4 contains them. #223
Conversation
…Reword algos as appropriate.
…le pending removals.
@tabatkins the Bikeshed build is still failing. Did you release a new Bikeshed yet? |
fullscreen.bs
Outdated
<p>To <dfn>fullscreen an <var>element</var></dfn>, set <var>element</var>'s <a>fullscreen flag</a> | ||
and <a for="top layer">add</a> it to its <a>node document</a>'s <a>top layer</a>. | ||
<p>To <dfn>fullscreen an <var>element</var></dfn>, set <var>element</var>'s <a>fullscreen flag</a>. | ||
If <var>element</var> is not currently [=in the top layer=] of its <a>node document</a>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is where the important behavioral change (not moving to the top of top layer) is. Once settled, can you add a note here describing the non-obvious consequences if the element is already in top layer? Right now it might be:
Note: If element is already in the top layer, it will not be moved, and may be obscured by other elements later in top layer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like the behavior we're going for, actually, is that an element can only be in the top layer for one reason at a time, so actually this might need to change a little more to properly reflect that. (And possibly allow it to be moved if it's currently in the top layer for fullscreen reasons, as per your comment.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have safeguards (exceptions notably) for this so we shouldn't change behavior unless necessary. Dialogs can't be fullscreened, Popovers can't be fullscreened (with #204 merged at least). Fullscreen elements also can't be made popovers (check popover validity algorithm prevents it). They can't be made dialogs either since you can't change the tag name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think here we should first check if the element is in top layer and if so remove it immediately. That will have the effect of moving it to the top of the stack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I've gone ahead and applied this - when fullscreening, we first request removal then add it, so it'll cycle to the end if it was already there.
I think the prose here looks good and it's just a question of what the behavior should be in two cases. For the "already in top layer case", I think it's a very rare situation in practice, but there are the situations I can think of worth testing:
@tabatkins what do you think about the second case here? To also respond to your PR description:
Do you have the test code available that you were trying?
Do you have open PRs for all specs that link to the IDs that will go away? If so I think it's fine to let the cross-spec links be broken for a short time.
I would say no. @annevk how have you done things for other specs? |
No, I was blocked on whatwg/meta#271, but I've gone ahead and unblocked myself there. The Bikeshed release is now public, 3.11.22.
I was just doing
No, I need to figure out how to get this info, I think it's available from WebRef. |
Yes, it's unaffected afaict.
Hm, we can make this work if necessary.
You already can't fullscreen a dialog, and #204 closes popovers when an element fullscreens. |
Thanks @tabatkins, this now builds! I've poked #204 to see if we can get that landed, although it doesn't block this PR. I think we can put interactions between fullscreen and other top layer-using features to the side, since as you point out That leaves pure uses of the Fullscreen API with multiple elements. I think the conservative thing to do is to conserve the existing behavior where we move an element within the top layer. I'm not aware of real-world uses of it, but it's not especially far-fetched and the web is big. I think the most straightforward approach is to call "remove an element from the top layer immediately" followed by " an element to the top layer", is that what you think we should do? |
Yeah, if we currently have compat with If it's already in the top layer but doesn't have the fullscreen flag, that means some other feature has put it in and we probably shouldn't touch it, at least not until we have the cross-feature agreement figured out. |
OK, I've tested the <style>
div {
padding: 1em;
display: grid;
place-items: center;
}
</style>
<div id="A" style="background-color:lavender">
<span>This is A. <button onclick="fs(event)">go/toggle fullscreen</button></span>
</div>
<div id="B" style="background-color: lemonchiffon">
<span>This is B. <button onclick="fs(event)">go/toggle fullscreen</button></span>
</div>
<script>
const divs = Array.from(document.querySelectorAll('div'));
function fs(event) {
let target = event.target.closest('div');
if (target === document.fullscreenElement) {
// Toggle between the two divs when already fullscreen.
target = divs.find((div) => div !== document.fullscreenElement);
}
console.log(`Requesting fullscreen for ${target.id}`);
target.requestFullscreen().then(() => {
console.log(`Success for ${target.id}`);
}, (error) => {
console.log(`Error for ${target.id}: ${error.message}`);
});
}
</script> As it turns out, only Chrome supports toggling between fullscreen elements like this. Firefox fails the toggle request with "Request for fullscreen was denied because requesting element is not a descendant of the current fullscreen element." Safari also rejects the In other words, the original hierarchy restrictions are still in Gecko and WebKit, see #140 for further links. @josepharhar @mfreed7 do you have preferences on how we handle this? |
We do sometimes leave a note or small appendix for cases like this. See https://fetch.spec.whatwg.org/#websocket-protocol (and in particular the source). I think that is warranted here as well given how long Fullscreen hosted top layer. |
@tabatkins can you update this to leave a section preserving the top layer IDs pointing to their new location in https://drafts.csswg.org/css-position-4/? |
IDs added. I think we're just waiting on final confirmation of the decision in #223 (comment), then? |
@tabatkins that's right, let me ping folks about that. |
To help decide on the flip-flop case I checked how <dialog id="A" style="background-color:lavender">
<span>This is A. <button onclick="show(event)">open/toggle dialog</button></span>
</dialog>
<dialog id="B" style="background-color: lemonchiffon">
<span>This is B. <button onclick="show(event)">open/toggle dialog</button></span>
</dialog>
<button onclick="show(event)">open/toggle dialog</button>
<script>
const dialogs = Array.from(document.querySelectorAll('dialog'));
function show(event) {
let dialog = dialogs.find((dialog) => !dialog.open);
if (!dialog) {
// Try to open the first one anyway, expect it to fail.
dialog = dialogs[0];
}
console.log(`Showing dialog ${dialog.id}`);
try {
dialog.showModal();
console.log(`Success for ${dialog.id}`);
} catch (error) {
console.log(`Error for ${dialog.id}: ${error.message}`);
}
}
</script> These are sibling To get the equivalent behavior for the fullscreen API, we should reject if the element is already in top layer stack, but we shouldn't add back a hierarchy restriction. @josepharhar @mfreed7 would that work for you? |
If this ends up being web compatible, I'm definitely supportive. It feels right to:
|
@mfreed7 sounds good! Let's hammer out the details of point 2 then, what happens for a second call to Bottom line first: no-op success when requesting fullscreen again matches current behavior. That's what this PR already does, so no changes required. The investigation: One scenario is calling button.onclick = () => {
const p1 = div.requestFullscreen();
const p2 = div.requestFullscreen();
// Does p2 reject and why?
} This is tested in element-request-fullscreen-twice.html and Chrome, Firefox and Safari all reject the second promise. Per spec (with #153 just merged) it should reject because the user gesture was consumed by the first call. Another scenario is calling button.onclick = () => {
const p = div.requestFullscreen();
// Does p reject if div is document.fullscreenElement?
} This is tested in element-request-fullscreen-same-element.html. That times out in Safari, I don't know why, so I tested this manually: button.onclick = () => {
if (!document.fullscreenElement) {
div.requestFullscreen().then(() => {
console.log('1st request succeeded');
}, (error) => {
console.log('1st request failed:', error.message);
});
} else {
div.requestFullscreen().then(() => {
console.log('2nd request succeeded');
}, (error) => {
console.log('2nd request failed:', error.message);
});
}
} I've found that Chrome, Firefox and Safari all resolve the 2nd promise, in other words it's a no-op. |
For testing, a think a single new test would cover this PR. It should have two sibling divs, A and B. Request fullscreen once per click in order A-B-A and assert that all requests succeed but the last is a no-op and that |
See the discussion at [1] for more context. This test requests fullscreen on A, then B, then A, where A and B are sibling divs. All three requests should succeed, but at the end, B should be left topmost (and the fullscreen element) but both A and B should be in the top layer. [1] whatwg/fullscreen#223 Change-Id: I3f35dda5b9eb1bc24201616bb5bb4949d20fd170
Yes, pretty sure that's how WebKit implements it already: https://searchfox.org/wubkat/rev/17b431999014409e4831dce71e69e0033d87ede5/Source/WebCore/dom/FullscreenManager.cpp#514-517 (If the test is failing, it's probably failing for different reasons fwiw) |
I believe it’s failing because WebKit doesn’t allow A and B to be siblings. |
…ng it, so it'll cycle to the end. whatwg#223
I've discussed the invocation style of the algorithms in https://drafts.csswg.org/css-position-4/#top-manip with @annevk. We've converged on something like this being best for Fullscreen and HTML:
I've filed w3c/csswg-drafts#8849 about the document argument, but for now I'll add suggestions to this PR and whatwg/html#9093 to align on this style. If w3c/csswg-drafts#8849 is resolved, it will be trivial edits to remove the document argument. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bunch of style changes to keep this spec's more archaic style, and also to match how the algorithms are invoked with how it's done in HTML.
…case, a=testonly Automatic update from web-platform-tests Add a test for fullscreen for the A/B/A case See the discussion at [1] for more context. This test requests fullscreen on A, then B, then A, where A and B are sibling divs. All three requests should succeed, and at the end, A should be topmost (and the fullscreen element) with both A and B in the top layer. [1] whatwg/fullscreen#223 Change-Id: I3f35dda5b9eb1bc24201616bb5bb4949d20fd170 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4501251 Commit-Queue: Mason Freed <[email protected]> Reviewed-by: Joey Arhar <[email protected]> Auto-Submit: Mason Freed <[email protected]> Cr-Commit-Position: refs/heads/main@{#1141456} -- wpt-commits: bf4540b22b7a2a6939d8cf7468c4ce76e48c3fef wpt-pr: 39828
There are conflicts from #204, I'll try to resolve... |
Thanks @tabatkins for w3c/csswg-drafts@0385164. I'll update this PR to drop the extra arguments. (Updated algorithms are at https://drafts.csswg.org/css-position-4/#top-manip.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes to adapt to w3c/csswg-drafts@0385164 and stick with <var>
as the rest of the spec does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is all good now IMHO, much nicer with the dropped document argument to many algorithms.
@annevk can you review this from the WebKit perspective?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is all good now IMHO, much nicer with the dropped document argument to many algorithms.
@annevk can you review this from the WebKit perspective?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all my concerns are editorial, but they would still be good to fix.
fullscreen.bs
Outdated
<li><p><a>Request removal from the top layer</a> given <var>element</var>. | ||
|
||
<li><a>Add to the top layer</a> given <var>element</var>. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only the second step is needed here looking at the algorithm for "add".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without the call to "request removal from the top layer", the assert would be hit, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. So we preserve the behavior but allow for slightly novel behavior in new APIs. I guess that's okay. If we don't end up using the new behavior though we should simplify this again.
Perhaps it's best to wait for @nt1m and merge this tomorrow. I can ping him.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what you mean by "allow for slightly novel behavior in new APIs". All APIs would cycle thru the algorithms in this same way, unless they wanted to get into the guts and directly manipulate the top layer list (which they shouldn't).
The only two behaviors that specs should end up landing on for "put something in the top layer when it's already there" are this (cycle it to the end of the list) and "fail", probably throwing an error when they do so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does kinda seem like unless they would always remove prior to adding they'd have to perform a contains check. Which would be the somewhat novel behavior, but not entirely novel as the old API technically allowed for that as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, specs have to either check if the element is already in top layer and treat it as an error, or call "request removal from the top layer" to get the moving behavior. The latter preserves the behavior mentioned in the last note in https://fullscreen.spec.whatwg.org/commit-snapshots/afd56a35f409e5595dd861f41390a1016ebd6aa2/#new-stacking-layer.
Co-authored-by: Anne van Kesteren <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fine aside from my one comment.
…case, a=testonly Automatic update from web-platform-tests Add a test for fullscreen for the A/B/A case See the discussion at [1] for more context. This test requests fullscreen on A, then B, then A, where A and B are sibling divs. All three requests should succeed, and at the end, A should be topmost (and the fullscreen element) with both A and B in the top layer. [1] whatwg/fullscreen#223 Change-Id: I3f35dda5b9eb1bc24201616bb5bb4949d20fd170 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4501251 Commit-Queue: Mason Freed <[email protected]> Reviewed-by: Joey Arhar <[email protected]> Auto-Submit: Mason Freed <[email protected]> Cr-Commit-Position: refs/heads/main@{#1141456} -- wpt-commits: bf4540b22b7a2a6939d8cf7468c4ce76e48c3fef wpt-pr: 39828
I've filed https://bugzilla.mozilla.org/show_bug.cgi?id=1834542 and https://bugs.webkit.org/show_bug.cgi?id=257199. @annevk do you want to approve this? |
🎉 Thanks all! |
Also reword algos as appropriate.
As far as Fullscreen is concerned, this is almost a no-op change, as things are merely moving. The only normative change that's relevant here is in the "fullscreen an element" algo, as it's no longer valid to add something to the top layer when it's already there (see next para for details). At the moment I've changed it to simply check if it's already in the top layer and only add if it's not, but this can be changed as necessary. (There are some other changes to the top-layer handling as it exists in Position 4, but they're in response to CSSWG decisions and are being discussed over there.)
The issue with adding something to the top layer that's already there is that, now that we have multiple things interacting with the top layer, they can have complex interactions of their own, and arbitrarily rearranging an element put in the top layer by some other process isn't necessarily safe. For example, a popover can be part of a popover stack, with each attached to the element below. Fullscreening the bottom popover must not just move that bottom popover to the end of the top layer and leave the rest of the popovers behind; it has to do something else, probably closing the popover (and thus closing its associated stack).
I'm not 100% sure how we want to handle the interaction of these separate features. I suspect it'll have to be something like each defining its own "hey you're being removed from the top layer" algo, which the others can invoke before they add the element to the top layer for their own purposes. But this'll need more thought; I went with what I felt was the simplest model for right now, where if you fullscreen something already in the top layer for other reasons, it just gets its flag and that's that.
(This is technically a behavior change per spec, but doesn't appear to be a behavior change in practice, at least in Chrome - if you fullscreen an element, show a modal, then ask to fullscreen the first element again, it does not move on top of the dialog, it stays where it is. But opening a dialog then fullscreening an element does successfully put the fullscreen over the dialog. I'm having trouble getting Firefox to successfully fullscreen something so I can test this.)
/cc @mfreed7 @josepharhar @nt1m @annevk
Currently this PR won't build because I'm using a new Bikeshed metadata to ignore the MDN issue; I should have a release out supporting this new metadata either today or tomorrow. (It won't build without the metadata either, since it's a fatal error to be missing an MDN anchor, too.).
Potentially we could kill both by keeping the ID in the spec, but just having it explicitly say that the definition has been moved to CSS Position. Would that be better?
More generally, for all the IDs that are being moved to Position, do you want to keep them in the spec with a redirect section?
Preview | Diff