Re: [CSSOM-view] Support centering an element when scrolling into view.

On Tue, May 22, 2012 at 4:17 PM, Thaddee Tyl <thaddee.tyl@gmail.com> wrote:

> A common pattern in the web is to use `element.scrollIntoView()` to
> show that element
> in the context of the web page. However, the design of scrollIntoView
> puts that element
> either at the very top or at the very bottom of the viewport.
>
> In most cases, web authors want to center that element. As a result,
> there is great duplication
> of code to make that work, and scrollIntoView gets rarely used, except
> for quick and dirty
> implementation of a search functionality.
>
> I suggest a solution to that in the following bug, copy and pasted below.
>
> All feedback is warmly welcome!
>
> https://www.w3.org/Bugs/Public/show_bug.cgi?id=17152
>
>
> ---
>
> The main reason why we might use `scrollIntoView()` is to bring an
> element into the viewport.
>
> However, showing that element at the top or at the bottom of the
> viewport is detrimental to understanding the context in which this
> element is. As a result, what authors really want is to center
> the element.
>
> I know we are implementing that in JS again and again throughout Firefox,
> and web developers are, too.
>
>
> Webkit has a method called
> `void scrollIntoViewIfNeeded(optional boolean center);`,
> which scrolls the page so that an element, if not completely shown,
> becomes completely shown, and appears vertically centered in the viewport
> if the boolean is true.
>
> The reason I bring this method up is to highlight its bad design.
>
> 1. Boolean flags are unreadable: it is unclear from reading
>   `scrollIntoViewIfNeeded(false)` what that `false` means, and even if
>   we know that it is about centering the element, which one, of `true`
>   and `false`, does indeed center the element.
>
> 2. We already have `void scrollIntoView(optional boolean top)`.
>   Having many methods whose intents are collinear is wrong.
>   Different methods should have orthogonal goals.
>
> I therefore suggest the following addition:
>
>    partial interface Element {
>      void scrollIntoView(ScrollPosition options);
>    };
>
>    dictionary ScrollPosition {
>      float top = 0.5;
>      float left = 0.0;
>      boolean notIfViewed = true;
>    };
>
> where `top` and `left` are meant as percentages of
> `max(0, scrollY - element.clientHeight)` and
> `max(0, scrollX - element.clientWidth)` respectively.
>
> If `notIfViewed` is true, and the element is completely in the viewport,
> then this method does nothing.
> If `notIfViewed` is true, and the element is partially hidden,
> then scroll just enough so that the element appears completely
> in the viewport.
>
> In all other cases, scroll so that the element is positioned at
> `options.top * max(0, scrollY - element.clientHeight)` with respect
> to the top border edge, and at
> `options.left * max(0, scrollX - element.clientWidth)` with respect
> to the left border edge.
>
> Overloading of `scrollIntoView` happens
> as described at <http://www.w3.org/TR/WebIDL/#idl-overloading>.
>
> An intended effect of this design is that calling
> `element.scrollIntoView({});` automatically does the right thing and
> centers the element on the screen, while you can still get the
> old behavior by calling `element.scrollIntoView()`.
>

while the intent of your proposal seems good, the details would need
tweaking, and general buy-in and implementation support would need to occur
before adopting; a couple of quick comments:

   - creating a new type ScrollPosition may be over-design, when a simpler
   signature may suffice
   - using top and left as ScrollPosition values is western writing system
   centric, and may need to be relativized to handle rl-tb and tb writing modes

Received on Wednesday, 23 May 2012 04:42:46 UTC