whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
8.16k stars 2.69k forks source link

Disable / customize scrolling behavior of Element.focus #834

Open RByers opened 8 years ago

RByers commented 8 years ago

From www-style discussion: when Element.focus() is used the UA may scroll the element into view (it's not immediately obvious to me if this is specified or not). In that case, there's currently no way to request the scrolling to be smooth. Perhaps focus should take an optional ScrollBehavior like Element.scrollIntoView now does?

domenic commented 8 years ago

Interesting. I am pretty sure this is not specced, but it probably should be! How interoperable is it? I assume this kind of scrolling only happens for .focus(), not for other methods of focusing like tabbing?

I think this is an eminently reasonable proposal, and would be happy to work on a PR or review one from you, if Blink is interested in implementing and nobody else objects.

zcorpan commented 8 years ago

Tabbing also scrolls, and as was pointed out in www-style, it would be nice if it was possible to control smooth scrolling for that using the scroll-behavior CSS property. Moving sequential navigation is also part of the HTML spec.

The dictionary to use for focus() would be either ScrollOptions (to be able to control only behavior) or ScrollIntoViewOptions (if you also want to control the position etc).

RByers commented 8 years ago

This isn't urgent from the blink implementation side, our implementation of CSS OM smooth scroll is temporarily on hold, but we do hope to resume soon.

tkent-google commented 8 years ago

"No scrolling" option is also necessary. There is such use case.

zcorpan commented 8 years ago

What is the use case?

tkent-google commented 8 years ago

Suppose that multiple-tabs like UI, and a scrollable tab has a focusable element. Let's call it "Tab-A".

  1. Tab-A is shown initially, and the element is focused.
  2. A user scroll the tab content by scroll bar. The focused element is scrolled out.
  3. The user selects another tab. Tab-A is hidden.
  4. The user selects Tab-A again. Want to call focus() for the focusable element in Tab-A, but we'd like to keep the last scroll position.

We'd like to do this in DevTools console tab of Google Chrome.

aFarkas commented 8 years ago

See also this use case for the no scroll behavior: https://discourse.wicg.io/t/improve-element-focus-method-with-options-or-provide-a-better-new-focus-method/1485/3

It would be great, if this feature would be easily feature detectable (i.e.: without trying to focus a hidden element or similar).

RByers commented 7 years ago

I just saw another scenario where disabling scrolling probably makes sense - when JS is focusing an element based on pointer hover (for TV use cases).

jihyerish commented 7 years ago

I just saw another scenario where disabling scrolling probably makes sense - when JS is focusing an element based on pointer hover (for TV use cases).

Generally, the input device for the TV is the remote controller. For LG Smart TV, an element is focused by the hover event (when people swing the remote controller). If there is an element which is partially visible in the scroll area, like below,

image

when hovering the element, focus event triggers the scroll behavior. On that case, the grid list scrolls too much, and it's really bad UX for TV. So, we block that behavior with a trick.

Can focus also have the no scrolling behavior?

jihyerish commented 7 years ago

I suggest adding scrollOption to Element.focus() for defining the scroll behavior.

Such as:

Element.focus(scrollOptions);

scrollOptions
{
  behavior: "auto" | "none" | "smooth",
  block: "start" | "end"
 }

scrollOptions refers to the scrollIntoViewOptions of Element.scrollIntoView().

Element.focus() currently triggers scrolling the element into view. The result is reasonable when focusing based on onkeydown. But when focusing by mouseover the element, focus event also triggers the scroll behavior.

Demo shows no scrolling behavior when focusing by mouseover. If the option isn't checked, it shows the result of the default scroll behavior triggered by Element.focus().

Similar discussion is in https://github.com/w3c/csswg-drafts/issues/1388.

domenic commented 7 years ago

This seems like a good solution to me. There are several Blink developers on this thread who seem interested; can we find other vendors interested in such an addition?

zcorpan commented 7 years ago

@RByers can you comment on whether there is implementation interest in chromium for @jihyerish's proposal?

@smaug---- can you comment on the same for Gecko?

RByers commented 7 years ago

That sounds like a good idea to me - I'd support implementing. It's up to @dtapuska on our input team to decide what priority we'd give it.

dtapuska commented 7 years ago

I've created 734166 to track the Chromium issue. We will work on figuring out what kind of priority to set to it. But it seems to make sense to me to do.

smaug---- commented 7 years ago

Looks reasonable to me.

smaug---- commented 7 years ago

Filed https://bugzilla.mozilla.org/show_bug.cgi?id=1374045 Need to have proper spec before implementation work.

zcorpan commented 7 years ago

Thank you!

@jihyerish would you be interested in working on a pull request for the standard? (Otherwise I can work on this, but not until August or so.)

FYI @cdumez @gregwhitworth

jihyerish commented 7 years ago

Yes, I'd like to upload a PR. Thank you! : )

rniwa commented 7 years ago

It's not great to use "block" to refer to a viewport location and then use "start" and "end" to refer to the top / bottom of the viewport given "start" and "end" usually refers to an inline direction.

It's not entirely clear what this means in a document in vertical writing mode, or more broadly any page that scrolls horizontally. In particular, it's possible for a document to have both horizontally and vertically scrollable. What does "start" of a viewport mean in such a page?

@smfr @grorg

jihyerish commented 7 years ago

What does "start" of a viewport mean in such a page?

I considered the block flow direction here. If the scrolling direction is top-to-bottom (vertical scrolling), let the beginning edge is the top edge and the ending edge is the bottom edge of the viewport. If the scrolling direction is left-to-right (horizontal scrolling), let the beginning edge is the left edge and the ending edge is the right edge of the viewport. If the scrolling direction is right-to-left (horizontal scrolling), let the beginning edge is the right edge and the ending edge is the left edge of the viewport.

Then, if the block dictionary member of options is start, the beginning edge of the viewport is aligned with the edge of the focused element which is on the same physical side of the beginning edge.

@rniwa It's a good point. : ) The inline base direction also need to be considered in this case.

RByers commented 7 years ago

@yi-gu just raised an interesting point - when you type into an already focused input box it runs the focus steps and causes it to scroll into view. Do we also need some way to customize/disable this focus-based scrolling?

jihyerish commented 7 years ago

when you type into an already focused input box it runs the focus steps and causes it to scroll into view

Does it means that an already focused input box calls scrollIntoView() even if it's already within the viewport and its position doesn't change?

I tested for the input box and found out: If there is a focused input box which is out of view and when I try to type into it, it scrolls into the view. (In Chrome, the input box is positioned at the center of the view, but in Firefox, it is positioned to the nearest edge of the view)

jihyerish commented 7 years ago

@RByers In the past, while adding "center" to ScrollLogicalPosition in CSSOM(see: https://github.com/w3c/csswg-drafts/pull/81), there was a suggestion[1] to specify a boolean value which considers the situation whether or not the element is completely in the view like below:

partial interface Element {
      void scrollIntoView(ScrollPosition options);
    };

    dictionary ScrollPosition {
      float top = 0.5;
      float left = 0.0;
      boolean notIfViewed = true;
      long offsetX = 0;
      long offsetY = 0;
    };

The suggestion referred "scrollIntoViewIfNeeded()" which is a non-standard feature. This API doesn't work if an element is already within the view. (As far as I know, it is still supported in Webkit.) I'm not sure the boolean value, "notIfViewed" in this suggestion was reflected when updating scrollIntoView() or ScrollLogicalPosition. @zcorpan could you check out about this?

I think the use case that you mentioned above also could be supported by focus(), if scrollIntoView() can handle the condition when the element is already within the view, and ScrollIntoViewOptions is added to focus() as a parameter.

[1] https://lists.w3.org/Archives/Public/www-style/2012May/0808.html, https://lists.w3.org/Archives/Public/www-style/2012Jun/0455.html

domenic commented 7 years ago

Hmm, I didn't mean to close this completely. Let me reopen. @zcorpan summarized the route we ended up taking in #2787 in https://github.com/w3c/csswg-drafts/pull/1805#issuecomment-337801758 .

Roughly, we now have el.focus({ preventScroll: true }). This is enough of a primitive that, in combination with IntersectionObserver and scrollIntoView(), you can customize scrolling on focus. But, it's not super-convenient for developers.

Before adding more developer-facing abilities to focus() we'd like to:

So: progress! But still worth keeping this bug open.

yattias commented 5 years ago

I just spent a bunch of time trying to figure out why my scroll function was not working. It turns out, that is due to the scroll behavior of element.focus()

Fuzzyma commented 2 years ago

Is there a way to get the same "no scroll" behavior when using the tab key? The current browser behavior is not sufficient because it doesn't detect if the element which is focused is behind another element. Therefore I want to disable it and implement my own version. I do NOT want to reimplement tabbing through focusable elements