Skip to content
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

Focusing algorithm is missing a "scroll the element into view" step #94

Open
cvrebert opened this issue Sep 3, 2015 · 21 comments
Open

Comments

@cvrebert
Copy link
Member

cvrebert commented Sep 3, 2015

(This is an intentional duplicate of https://www.w3.org/Bugs/Public/show_bug.cgi?id=27913 since that bug is in the wrong WG and an obscure Bugzilla Component.)
Basically, https://html.spec.whatwg.org/multipage/interaction.html#focus-update-steps doesn't seem to mention anything about scrolling the focused element into view if it was outside the viewport, even though all browsers do this in practice (simple testcase) most of the time (there are apparently some exceptional cases). So a step (presumably invoking https://drafts.csswg.org/cssom-view/#scroll-an-element-into-view) should be added to make the spec reflect reality. I haven't dug deep enough to suggest exactly where in that algorithm the new step should be inserted.

@annevk
Copy link
Member

annevk commented Sep 3, 2015

Perhaps @rodneyrehm would like to take a stab at this himself?

@rodneyrehm
Copy link

Perhaps @rodneyrehm would like to take a stab at this himself?

sure, if you tell me what I'm supposed to do :)

I haven't dug deep enough to suggest exactly where in that algorithm the new step should be inserted.

The scroll event is emitted after focus in Gecko, Trident and Blink (pimped the simple testcase). Since focus is synchronous and scroll is asynchronous, that order does not necessarily have to be the order of invocation, but let's assume events are dispatched in order they were received. Looking at 5.6.9 Navigating to a fragment identifier we can see the actual scrolling being done as the last step of the sequence.

Based on that I'd suggest to add "executing the scroll an element into view" as step 6 of the focus activation sequence, i.e. after the event received focus.


While we're on the topic, I wonder if it is feasible to use the focus event to prevent the "scroll element into view" step from happening. The focus event is synchronous and currently not cancelable. Is it possible to make it cancelable, but instead of preventing focus from happening itself, we prevent the subsequent scrolling?

@annevk
Copy link
Member

annevk commented Sep 3, 2015

@rodneyrehm you basically want to patch "source" within this repository, but see README.md for more detailed instructions. You also want to use the HTML Standard as reference, not its W3C copy.

I think your suggestion is correct though and would recommend you make a pull request. @Hixie and maybe @smaug---- would have to review it.

@cvrebert
Copy link
Member Author

cvrebert commented Sep 3, 2015

So, this being The Web™, of course there's an extra complication. When the focused element is outside the viewport:

  • Chrome & Safari scroll the focused element to the center of the viewport.
  • Firefox & MS Edge scroll the focused element to the near edge of the viewport. If the element was above the viewport, they scroll so the element is at the top of the viewport. If the element was below the viewport, they scroll so the element is at the bottom of the viewport.
  • (Included only for completeness' sake) Presto scrolls the focused element to the top of the viewport.

Testcase: http://jsfiddle.net/cvrebert/nwzfo2dr/

@rodneyrehm
Copy link

@cvrebert true, but shouldn't the scroll an element sequence cover that?

@cvrebert
Copy link
Member Author

cvrebert commented Sep 3, 2015

@rodneyrehm Unless I'm missing something, https://drafts.csswg.org/cssom-view/#scroll-an-element-into-view scrolls an element to either the top or the bottom of the viewport, depending on whether the "align to top" flag is set. So (a) specing the "scroll into center" behavior isn't as easy as simply delegating to a CSSOM View algorithm (at least until http://w3bug.com/17152 gets fixed) (b) specing the "scroll to near edge" behavior would seem to require the HTML spec to compute the "align to top" flag itself.

But my main point was that specing either behavior means that two of the browsers will need to change their existing behavior. Are the vendors willing to do that?

@cvrebert
Copy link
Member Author

cvrebert commented Sep 3, 2015

Additionally, in my testing, all the current major browsers only perform a scroll if the element isn't within the viewport (akin to the nonstandard scrollIntoViewIfNeeded() method), but https://drafts.csswg.org/cssom-view/#scroll-an-element-into-view does not include such a "is the element already within the viewport?" check. Hopefully that logic already exists somewhere and we can just reference it in a condition in the new step.

@rodneyrehm
Copy link

I have to admit that I care less about the point the focused element is scrolled to and more about the missing feature to prevent that from happening at all. That said, I understand and agree with all raised concerns. Simply appending a reference to the scroll element into view algorithm to the focus activation sequence won't cut it.

@annevk
Copy link
Member

annevk commented Sep 4, 2015

@zcorpan should probably weigh in here. When it comes to scrolling there's also something to be said to give user agents some leeway in how to handle things since it's a user interface matter. Perhaps the CSSOM algorithm needs to account for that.

@zcorpan
Copy link
Member

zcorpan commented Sep 4, 2015

This is the same feature as in https://www.w3.org/Bugs/Public/show_bug.cgi?id=17152 AFAICT. I'm happy to provide hooks HTML needs here.

@cvrebert
Copy link
Member Author

@zcorpan So is anything blocking you on adding the hooks (aside from there not being enough hours in the day)?

@zcorpan
Copy link
Member

zcorpan commented Sep 14, 2015

Nothing in particular, no.

@usmonster
Copy link

Hello! Not sure if here's the proper forum, but I just wanted to raise a concern about a potential exceptional case where the scrolling step should probably be skipped: when focus is restored to the previously-active element after a modal dialog is closed.

This clause appears in the referenced document:

When the dialog is closed or cancelled focus should return to the element in the application which had focus before the dialog is invoked. This is usually the control which opened the dialog.

In cases where this element was not inside the viewport at the moment the dialog was first opened, executing the scrolling step will usually cause undesirable, disorienting scrolling.

On the other hand, in most major browsers (at least in the ones I've tested), closing a dialog that was opened via Window.{alert,confirm,prompt} will restore focus to the previously-active element without scrolling. This behavior seems correct and intuitive to me, and should probably be mentioned explicitly both in the spec for focus behavior and in the WIA-ARIA guidelines for modal dialog widgets, if you agree--a11y experts, please weigh in here.

For some more background on this issue with concrete use cases and demos, please see the corresponding jQuery UI ticket as an example of why I believe this case should be handled as an exception:
http://bugs.jqueryui.com/ticket/10686

I hope this is clear, and please don't hesitate to let me know if there's a better place to ask about this. Thanks!

@rodneyrehm
Copy link

On the other hand, in most major browsers (at least in the ones I've tested), closing a dialog that was opened via Window.{alert,confirm,prompt} will restore focus to the previously-active element without scrolling.

Those functions block script execution until the system dialogs are closed. document.activeElement does not change when calling window.alert() - and if it does, it is not observable by script. My argument is, that focus cannot be restored in this case, because it never changed. Because focus is not restored, the scrolling step would never be performed anyway.

The <dialog> element, currently implemented in Google Chrome, behaves differently in that regard, because document.activeElement actually changes between opening and closing the dialog. So here we might see scrolling upon closing the dialog.

@usmonster
Copy link

Those functions block script execution until the system dialogs are closed. document.activeElement does not change when calling window.alert() - and if it does, it is not observable by script. My argument is, that focus cannot be restored in this case, because it never changed. Because focus is not restored, the scrolling step would never be performed anyway.

Thanks for the quick response! That's an excellent point and an absolutely valid argument about the technical behavior of those functions. I hadn't fully reasoned about why, exactly, their closing behavior seemed exceptional compared to most modal dialog widget implementations I've seen, including Chrome's implementation of the <dialog> element. Since the focus does shift to an actual element when a dialog opens in the case of the <dialog> element and dialog widgets, of course they will have to manage restoring focus, while alert() and family do not.

While the technical differences are now clearer, my counter-argument is that the perceived behavioral differences should probably still be reconciled so that the recommendation for what should happen when closing a modal dialog of any kind (including <dialog>, alert(), widgets, et al.) is defined and consistent for accessibility's sake.

The primary use case family I can think of where dialog "close, focus, scroll" behavior would be most disruptive is any case where opening the dialog was triggered by an event listener attached to some ancestor of the (out-of-viewport) active element (e.g. shortcut keys, scroll listeners, etc.). Also dialogs triggered by something other than user input.

Some open questions are:

  • Are these valid use cases?
  • Are they worth mentioning in the spec?
  • Should the focus-restoring behavior when closing a modal dialog in these cases be exceptional (i.e. try to avoid scrolling)?
  • Is the current dialog "close, focus, scroll" behavior a good pattern in terms of accessibility?
  • Should I open a separate issue for this?

Thoughts? Thanks again for your feedback!

@cvrebert
Copy link
Member Author

@zcorpan Any progress in adding the requisite cssom-view hooks?

@zcorpan zcorpan self-assigned this Nov 30, 2015
@zcorpan
Copy link
Member

zcorpan commented Nov 30, 2015

No :-( Sorry for delaying this. Will fix this week.

@zcorpan
Copy link
Member

zcorpan commented Dec 3, 2015

WIP w3c/csswg-drafts#81

@cvrebert
Copy link
Member Author

@zcorpan Great! And what about either force/evenIfViewed/scrollIntoViewIfNeeded() or an "is the given element in view?" algorithm, so as to address #94 (comment) ?

@mstange
Copy link

mstange commented Mar 17, 2016

Has it been decided whether the scroll into view step should honor the scroll-behavior property? I just opened https://bugzilla.mozilla.org/show_bug.cgi?id=1257600 for Firefox on this - at the moment, focus scrolls are always instant in Firefox.

@zcorpan
Copy link
Member

zcorpan commented Mar 18, 2016

It probably should, but that is not specified yet. See
http://www.w3.org/mid/CAFUtAY-bA1dVwd9PBRQxMEAM1rvkv7WLRwFef_xxbS1f-TRNXA@mail.gmail.com
and
#834

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

7 participants