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

On Wed, 23 May 2012 00:17:13 +0200, 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()`.

Currently, scrollIntoView({}) is the same as scrollIntoView(). But I  
suppose it's still OK to change that.

On Wed, 23 May 2012 07:50:36 +0200, Thaddee Tyl <thaddee.tyl@gmail.com>  
wrote:

> On Tue, May 22, 2012 at 9:41 PM, Glenn Adams <glenn@skynav.com> wrote:
>> 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
>
> I didn't see any WebIDL way to do that, and it seems that this is how  
> all specs
> do it. There is no requirement to map that to a type.
>
>> 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
>
> That is very true. I actually thought about that, and made it so that
> we wouldn't
> need to use {right:0} or such (indeed, {left:1} does that).
>
> Maybe something like that would be better:
>
>   dictionary ScrollPosition {
>     float vertical = 0.5;
>     float horizontal = 0.0;
>     boolean notIfViewed = true;
>   };
>
> with the `horizontal` field being relative to the left in ltr and
> relative to the right in rtl.

This only helps for LTR and RTL, but not for vertical writing modes. Per  
current spec, scrollIntoView(true) aligns the block start, e.g. right for  
vertical-lr.

The current spec has block = "start" and block = "end". Should we add  
"center"? Should we add numbers? Replace with numbers?

Should it be possible to get the "nearest edge"?:

> 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.

https://github.com/whatwg/html/issues/94#issuecomment-137577168

The spec currently does this in the inline base direction.

One way to support that is to let the dictionary members not have default  
values, and use the nearest edge in that case. It means you have to  
specify something if you want center instead. Another way is to have a  
"nearest" value.

On Wed, 20 Jun 2012 00:24:50 +0200, Thaddee Tyl <thaddee.tyl@gmail.com>  
wrote:

> I have written a more formal description of the behavior of my
> proposal at <https://www.w3.org/Bugs/Public/show_bug.cgi?id=17152#c2>,
> which I hope addresses most issues. I have tried as much as I could to
> rely on terms already defined by the current draft.
>
> As for Robert's concerns, I have dodged the issue by using an
> ill-specified part of the current draft (or rather, a part of the
> draft that isn't CSS-regions-aware).
>
> I believe the correct way to handle elements that are fragmented
> between several scrollable containers is the following:
>
> If the scrolling box / boxes is / are associated with an element:
> - Consider each fraction of the element that is broken along multiple  
> scrollable
> ancestors as independent.
> - For each of those fractions, apply the scrollIntoView algorithm as if  
> its
> corresponding scrolling box was the toplevel window.
> - Then, apply the usual scrollIntoView algorithm using the element's
> complete bounding box.
>
> By the way, this algorithm does conform to what major browsers do,
> but does not conform to what is currently specified, afaik.
> Indeed, applying scrollIntoView to an element inside a scrolling box
> should not make the toplevel viewport change according to spec.
> In browsers, however, the iframe does in turn get scrolled into view
> (which I believe is the right thing to do).

The spec does scroll ancestors:

"run these steps for each ancestor element or viewport that establishes a  
scrolling box scrolling box, in order of innermost to outermost scrolling  
box:"

On Wed, 20 Jun 2012 01:33:50 +0200, Thaddee Tyl <thaddee.tyl@gmail.com>  
wrote:

> From feedback I have received on Twitter, some people would rather
> rename "evenIfViewed" (from the proposal) to "evenIfAlreadyInView".

That seems a bit long?

> Also, some people are interested in being able to add an offset, which
> would require this:
>
>     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;
>     };

If we have a way to specify offsets, do we also need more than "start",  
"center", "end" in block and inline directions?

Should it be possible to specify a scroll offset for following fragment  
links also? With a CSS property maybe?

-- 
Simon Pieters
Opera Software

Received on Thursday, 3 December 2015 13:42:07 UTC